class FitVariable(traits.HasTraits): """represents a variable in a fit. E.g. the standard deviation in a gaussian fit""" name = traits.Str initialValue = traits.Float calculatedValue = traits.Float stdevError = traits.Float traits_view = traitsui.View( traitsui.HGroup( traitsui.Item("name", show_label=False, style="readonly", width=0.2, resizable=True), traitsui.Item("initialValue", label="initial", show_label=True, resizable=True), traitsui.Item("calculatedValue", label="calculated", show_label=True, format_str="%G", style="readonly", width=0.2, resizable=True), traitsui.Item("stdevError", show_label=False, format_str=u"\u00B1%G", style="readonly", resizable=True)))
def make_view(self): return ui.View( ui.HGroup( ui.Item(name='v_list', editor=ui.EnumEditor(values=[str(v) for v in self.v_list])), ui.Item(name='plot', label="", editor=enable.ComponentEditor(), show_label=False) ) )
class CalculatedParameter(traits.HasTraits): """represents a number calculated from a fit. e.g. atom number """ name = traits.Str value = traits.Float traits_view = traitsui.View( traitsui.HGroup( traitsui.Item("name", show_label=False, style="readonly"), traitsui.Item("value", show_label=False, format_str="%G", style="readonly")))
class ExampleScene(TracerScene): source_y = t_api.Range(0., 5., 2.) source_z = t_api.Range(0., 5., 1.) def __init__(self): # The energy bundle we'll use for now: nrm = 1 / (N.sqrt(2)) direct = N.c_[[0, -nrm, nrm], [0, 0, -1]] position = N.tile(N.c_[[0, self.source_y, self.source_z]], (1, 2)) self.bund = RayBundle(vertices=position, directions=direct, energy=N.r_[1, 1]) # The assembly for ray tracing: rot1 = N.dot(G.rotx(N.pi / 4)[:3, :3], G.roty(N.pi)[:3, :3]) surf1 = rect_one_sided_mirror(width=10, height=10) surf1.set_rotation(rot1) surf2 = rect_one_sided_mirror(width=10, height=10) self.assembly = Assembly(objects=[surf1, surf2]) TracerScene.__init__(self, self.assembly, self.bund) @t_api.on_trait_change('_scene.activated') def initialize_camere(self): self._scene.mlab.view(0, -90) self._scene.mlab.roll(0) @t_api.on_trait_change('source_y, source_z') def bundle_move(self): position = N.tile(N.c_[[0, self.source_y, self.source_z]], (1, 2)) self.bund.set_vertices(position) self.plot_ray_trace() view = tui.View( tui.Item('_scene', editor=SceneEditor(scene_class=MayaviScene), height=400, width=300, show_label=False), tui.HGroup('-', 'source_y', 'source_z'))
class CameraUI(traits.HasTraits): """Camera settings defines basic camera settings """ camera_control = traits.Instance(Camera, transient = True) cameras = traits.List([_NO_CAMERAS],transient = True) camera = traits.Any(value = _NO_CAMERAS, desc = 'camera serial number', editor = ui.EnumEditor(name = 'cameras')) search = traits.Button(desc = 'camera search action') _is_initialized= traits.Bool(False, transient = True) play = traits.Button(desc = 'display preview action') stop = traits.Button(desc = 'close preview action') on_off = traits.Button('On/Off', desc = 'initiate/Uninitiate camera action') gain = create_range_feature('gain',desc = 'camera gain',transient = True) shutter = create_range_feature('shutter', desc = 'camera exposure time',transient = True) format = create_mapped_feature('format',_FORMAT, desc = 'image format',transient = True) roi = traits.Instance(ROI,transient = True) im_shape = traits.Property(depends_on = 'format.value,roi.values') im_dtype = traits.Property(depends_on = 'format.value') capture = traits.Button() save_button = traits.Button('Save as...') message = traits.Str(transient = True) view = ui.View(ui.Group(ui.HGroup(ui.Item('camera', springy = True), ui.Item('search', show_label = False, springy = True), ui.Item('on_off', show_label = False, springy = True), ui.Item('play', show_label = False, enabled_when = 'is_initialized', springy = True), ui.Item('stop', show_label = False, enabled_when = 'is_initialized', springy = True), ), ui.Group( ui.Item('gain', style = 'custom'), ui.Item('shutter', style = 'custom'), ui.Item('format', style = 'custom'), ui.Item('roi', style = 'custom'), ui.HGroup(ui.Item('capture',show_label = False), ui.Item('save_button',show_label = False)), enabled_when = 'is_initialized', ), ), resizable = True, statusbar = [ ui.StatusItem( name = 'message')], buttons = ['OK']) #default initialization def __init__(self, **kw): super(CameraUI, self).__init__(**kw) self.search_cameras() def _camera_control_default(self): return Camera() def _roi_default(self): return ROI() #@display_cls_error def _get_im_shape(self): top, left, width, height = self.roi.values shape = (height, width) try: colors = _COLORS[self.format.value] if colors > 1: shape += (colors,) except KeyError: raise NotImplementedError('Unsupported format') return shape #@display_cls_error def _get_im_dtype(self): try: return _DTYPE[self.format.value] except KeyError: raise NotImplementedError('Unsupported format') def _search_fired(self): self.search_cameras() #@display_cls_error def search_cameras(self): """ Finds cameras if any and selects first from list """ try: cameras = get_number_cameras() except Exception as e: cameras = [] raise e finally: if len(cameras) == 0: cameras = [_NO_CAMERAS] self.cameras = cameras self.camera = cameras[0] #@display_cls_error def _camera_changed(self): if self._is_initialized: self._is_initialized= False self.camera_control.close() self.message = 'Camera uninitialized' #@display_cls_error def init_camera(self): self._is_initialized= False if self.camera != _NO_CAMERAS: self.camera_control.init(self.camera) self.init_features() self._is_initialized= True self.message = 'Camera initialized' #@display_cls_error def _on_off_fired(self): if self._is_initialized: self._is_initialized= False self.camera_control.close() self.message = 'Camera uninitialized' else: self.init_camera() #@display_cls_error def init_features(self): """ Initializes all features to values given by the camera """ features = self.camera_control.get_camera_features() self._init_single_valued_features(features) self._init_roi(features) #@display_cls_error def _init_single_valued_features(self, features): """ Initializes all single valued features to camera values """ for name, id in list(_SINGLE_VALUED_FEATURES.items()): feature = getattr(self, name) feature.low, feature.high = features[id]['params'][0] feature.value = self.camera_control.get_feature(id)[0] #@display_cls_error def _init_roi(self, features): for i,name in enumerate(('top','left','width','height')): feature = getattr(self.roi, name) low, high = features[FEATURE_ROI]['params'][i] value = self.camera_control.get_feature(FEATURE_ROI)[i] try: feature.value = value finally: feature.low, feature.high = low, high @traits.on_trait_change('format.value') def _on_format_change(self, object, name, value): if self._is_initialized: self.camera_control.set_preview_state(STOP_PREVIEW) self.camera_control.set_stream_state(STOP_STREAM) self.set_feature(FEATURE_PIXEL_FORMAT, [value]) @traits.on_trait_change('gain.value,shutter.value') def _single_valued_feature_changed(self, object, name, value): if self._is_initialized: self.set_feature(object.id, [value]) #@display_cls_error def set_feature(self, id, values, flags = 2): self.camera_control.set_feature(id, values, flags = flags) @traits.on_trait_change('roi.values') def a_roi_feature_changed(self, object, name, value): if self._is_initialized: self.set_feature(FEATURE_ROI, value) try: self._is_initialized= False self.init_features() finally: self._is_initialized= True #@display_cls_error def _play_fired(self): self.camera_control.set_preview_state(STOP_PREVIEW) self.camera_control.set_stream_state(STOP_STREAM) self.camera_control.set_stream_state(START_STREAM) self.camera_control.set_preview_state(START_PREVIEW) #@display_cls_error def _stop_fired(self): self.camera_control.set_preview_state(STOP_PREVIEW) self.camera_control.set_stream_state(STOP_STREAM) self.error = '' #@display_cls_error def _format_changed(self, value): self.camera_control.set_preview_state(STOP_PREVIEW) self.camera_control.set_stream_state(STOP_STREAM) self.camera_control.set_feature(FEATURE_PIXEL_FORMAT, [value],2) #@display_cls_error def _capture_fired(self): self.camera_control.set_stream_state(STOP_STREAM) self.camera_control.set_stream_state(START_STREAM) im = self.capture_image() plt.imshow(im) plt.show() def capture_image(self): im = numpy.empty(shape = self.im_shape, dtype = self.im_dtype) self.camera_control.get_next_frame(im) return im.newbyteorder('>') def save_image(self, fname): """Captures image and saves to format guessed from filename extension""" im = self.capture_image() base, ext = os.path.splitext(fname) if ext == '.npy': numpy.save(fname, im) else: im = toimage(im) im.save(fname) def _save_button_fired(self): f = pyface.FileDialog(action = 'save as') #wildcard = self.filter) if f.open() == pyface.OK: self.save_image(f.path) def capture_HDR(self): pass def __del__(self): try: self.camera_control.set_preview_state(STOP_PREVIEW) self.camera_control.set_stream_state(STOP_STREAM) except: pass
class SplineExplorer(traits.HasTraits): """A simple UI to adjust the parameters and view the resulting splines.""" v_min = traits.Float(0) v_max = traits.Float(15) a_min = traits.Float(-5) a_max = traits.Float(5) j_min = traits.Float(-2.5) j_max = traits.Float(2.5) mass = traits.Float(400) q_i = traits.Float v_i = traits.Float a_i = traits.Float t_i = traits.Float q_f = traits.Float(100) v_f = traits.Float(0) a_f = traits.Float(0) t_f = traits.Float(18) plot_names = traits.List( ["Position", "Jerk", "Velocity", "Power", "Acceleration"]) active_plots = traits.List target_type = traits.Enum(('Position', 'Velocity', 'Acceleration', 'Time')) plot_container = traits.Instance(Container) recalculate = menu.Action(name="Recalculate", action="recalc") dump = menu.Action(name="Print", action="dump") save = menu.Action(name="Save", action="save") trait_view = ui.View(ui.HGroup( ui.VGroup( ui.Item(name='target_type', label='Target'), ui.VGroup(ui.Item(name='active_plots', show_label=False, editor=ui.CheckListEditor(cols=3, name='plot_names'), style='custom'), label='Show Plots', show_border=True), ui.VGroup(ui.Item(name='q_i', label='Position'), ui.Item(name='v_i', label='Velocity'), ui.Item(name='a_i', label='Acceleration'), ui.Item(name='t_i', label='Time'), label='Initial Conditions', show_border=True), ui.VGroup(ui.Item( name='q_f', label='Position', enabled_when="target_type not in ('Velocity', 'Acceleration')" ), ui.Item(name='v_f', label='Velocity', enabled_when="target_type != 'Acceleration'"), ui.Item(name='a_f', label='Acceleration'), ui.Item(name='t_f', label='Time', enabled_when="target_type == 'Time'"), label='Final Conditions:', show_border=True), ui.VGroup(ui.Item(name='v_min', label='Min Velocity'), ui.Item(name='v_max', label='Max Velocity'), ui.Item(name='a_min', label='Min Acceleration'), ui.Item(name='a_max', label='Max Acceleration'), ui.Item(name='j_min', label='Min Jerk'), ui.Item(name='j_max', label='Max Jerk'), ui.Item(name='mass', label='Vehicle Mass'), label='Constraints', show_border=True)), ui.Item('plot_container', editor=ComponentEditor(), show_label=False)), title='Cubic Spline Explorer', handler=SEButtonHandler(), buttons=[recalculate, dump, save], resizable=True, width=1000) def __init__(self): super(SplineExplorer, self).__init__() self.active_plots = self.plot_names[:] self.active_plots.remove("Power") self.calc() def calc(self): try: self.solver = TrajectorySolver(self.v_max, self.a_max, self.j_max, self.v_min, self.a_min, self.j_min) self.initial = Knot(self.q_i, self.v_i, self.a_i, self.t_i) self.final = Knot(self.q_f, self.v_f, self.a_f, self.t_f) if self.target_type == 'Position': self.spline = self.solver.target_position( self.initial, self.final) elif self.target_type == 'Velocity': self.spline = self.solver.target_velocity( self.initial, self.final) elif self.target_type == 'Acceleration': self.spline = self.solver.target_acceleration( self.initial, self.final) elif self.target_type == 'Time': self.spline = self.solver.target_time(self.initial, self.final) pos = vel = accel = jerk = power = False if "Position" in self.active_plots: pos = True if "Velocity" in self.active_plots: vel = True if "Acceleration" in self.active_plots: accel = True if "Jerk" in self.active_plots: jerk = True if "Power" in self.active_plots: power = True self.plotter = CSplinePlotter(self.spline, self.v_max, self.a_max, self.j_max, self.v_min, self.a_min, self.j_min, mass=self.mass, plot_pos=pos, plot_vel=vel, plot_accel=accel, plot_jerk=jerk, plot_power=power) self.plot_container = self.plotter.container except: self.initial = None self.final = None self.spline = None self.plot_container = Container() def display(self): self.configure_traits() def get_save_filename(self): """Get a filename from the user via a FileDialog. Returns the filename.""" dialog = FileDialog(action="save as", default_filename="spline_00", wildcard="*.png") dialog.open() if dialog.return_code == OK: return dialog.path def save(self, path): """Save an image of the plot. Does not catch any exceptions.""" # Create a graphics context of the right size win_size = self.plot_container.outer_bounds plot_gc = chaco.PlotGraphicsContext(win_size) #plot_gc.set_fill_color("transparent") # Place the plot component into it plot_gc.render_component(self.plot_container) # Save out to the user supplied filename plot_gc.save(path) def _active_plots_changed(self): self.calc() def _target_type_changed(self): self.calc()
class Berth(Sim.Process, traits.HasTraits): label = traits.Str platform_index = traits.Int station_id = traits.Int vehicle = traits.Instance('pyprt.sim.vehicle.BaseVehicle', None) _busy = traits.Bool _unload = traits.Bool _load = traits.Bool _msg_id = traits.Int _pax = traits.List(traits.Instance('pyprt.sim.events.Passenger')) traits_view = ui.View(ui.HGroup(ui.Item(name='vehicle', editor = ui.TextEditor()), ui.Item('busy'))) def __init__(self, label, station_id, vehicle, **tr): Sim.Process.__init__(self, name=label) traits.HasTraits.__init__(self, **tr) self.label = label self.station_id = station_id self.vehicle = vehicle # Control flags/settings for the run loop self._busy = False self._unload = False self._load = False self._msg_id = api.NONE_ID self._pax = [] def __str__(self): return str( (self.label, str(self.vehicle), str(self._busy)) ) def is_empty(self): """Returns True if the berth is not occupied by a vehicle.""" return False if self.vehicle else True def unload(self, msg_id, passengers): self._unload = True self._msg_id = msg_id self._pax = passengers if self.passive: Sim.reactivate(self, prior=True) def load(self, msg_id, passengers): self._load = True self._msg_id = msg_id self._pax = passengers if self.passive: Sim.reactivate(self, prior=True) def is_busy(self): return self._busy def run(self): station = common.stations[self.station_id] while True: # Unloading if self._unload: for pax in reversed(self.vehicle.passengers): self._unload = False self._busy = True yield Sim.hold, self, pax.unload_delay del self.vehicle.passengers[-1] # pax that left vehicle pax.loc = self.station pax.trip_end = Sim.now() if self.station_id == pax.dest_station.ID: pax.trip_success = True common.delivered_pax.add(pax) logging.info("T=%4.3f %s delivered to %s by %s. Unloaded in berth %s", Sim.now(), pax, self.station_id, self.vehicle, self.label) self._busy = False if station.passive(): Sim.reactivate(station, prior = True) # Loading elif self._load: for pax in self._pax: self._load = False self._busy = True s_notify = api.SimNotifyPassengerLoadStart() s_notify.vID = self.vehicle.ID s_notify.sID = self.station_id s_notify.pID = pax.ID common.interface.send(api.SIM_NOTIFY_PASSENGER_LOAD_START, s_notify) yield Sim.hold, self, pax.load_delay self.vehicle.passengers.append(pax) pax.trip_boarded = Sim.now() pax.loc = self.vehicle logging.info("T=%4.3f %s loaded into %s at station %s", Sim.now(), pax, self.vehicle, self.station_id) e_notify = api.SimNotifyPassengerLoadEnd() e_notify.vID = self.vehicle.ID e_notify.sID = self.station_id e_notify.pID = pax.ID common.interface.send(api.SIM_NOTIFY_PASSENGER_LOAD_END, e_notify) # If using the LOBBY policy, notify that passenger load command # has completed. if self._load_msgID: cmd_notify = api.SimCompletePassengerLoadVehicle() cmd_notify.msgID = self._msgID cmd_notify.vID = self.vehicle.ID cmd_notify.sID = self.station_id cmd_notify.pID = pax.ID common.interface.send(api.SIM_COMPLETE_PASSENGER_LOAD_VEHICLE, cmd_notify) self._load_msgID = None self._busy = False if station.passive(): Sim.reactivate(station, prior = True) else: assert not self._busy yield Sim.passivate, self
class Fit(traits.HasTraits): name = traits.Str(desc="name of fit") function = traits.Str(desc="function we are fitting with all parameters") variablesList = traits.List(FitVariable) calculatedParametersList = traits.List(CalculatedParameter) xs = None # will be a scipy array ys = None # will be a scipy array zs = None # will be a scipy array performFitButton = traits.Button("Perform Fit") getInitialParametersButton = traits.Button("Guess Initial Values") drawRequestButton = traits.Button("Draw Fit") autoFitBool = traits.Bool( False, desc= "Automatically perform this Fit with current settings whenever a new image is loaded" ) autoGuessBool = traits.Bool( False, desc= "Whenever a fit is completed replace the guess values with the calculated values (useful for increasing speed of the next fit)" ) autoDrawBool = traits.Bool( False, desc= "Once a fit is complete update the drawing of the fit or draw the fit for the first time" ) logBool = traits.Bool( False, desc="Log the calculated and fitted values with a timestamp") logFile = traits.File(desc="file path of logFile") imageInspectorReference = None #will be a reference to the image inspector fitting = traits.Bool(False) #true when performing fit fitted = traits.Bool( False) #true when current data displayed has been fitted fitSubSpace = traits.Bool( False) #true when current data displayed has been fitted startX = traits.Int startY = traits.Int endX = traits.Int endY = traits.Int fittingStatus = traits.Str() fitThread = None physics = traits.Instance(physicsProperties.PhysicsProperties) #status strings notFittedForCurrentStatus = "Not Fitted for Current Image" fittedForCurrentImageStatus = "Fit Complete for Current Image" currentlyFittingStatus = "Currently Fitting..." failedFitStatus = "Failed to finish fit. See logger" fitSubSpaceGroup = traitsui.VGroup( traitsui.Item("fitSubSpace", label="Fit Sub Space"), traitsui.VGroup(traitsui.HGroup(traitsui.Item("startX"), traitsui.Item("startY")), traitsui.HGroup(traitsui.Item("endX"), traitsui.Item("endY")), visible_when="fitSubSpace"), label="Fit Sub Space", show_border=True) generalGroup = traitsui.VGroup(traitsui.Item("name", label="Fit Name", style="readonly", resizable=True), traitsui.Item("function", label="Fit Function", style="readonly", resizable=True), fitSubSpaceGroup, label="Fit", show_border=True) variablesGroup = traitsui.VGroup(traitsui.Item( "variablesList", editor=traitsui.ListEditor(style="custom"), show_label=False, resizable=True), show_border=True, label="parameters") derivedGroup = traitsui.VGroup(traitsui.Item( "calculatedParametersList", editor=traitsui.ListEditor(style="custom"), show_label=False, resizable=True), show_border=True, label="derived values") buttons = traitsui.VGroup( traitsui.HGroup(traitsui.Item("autoFitBool"), traitsui.Item("performFitButton")), traitsui.HGroup(traitsui.Item("autoGuessBool"), traitsui.Item("getInitialParametersButton")), traitsui.HGroup(traitsui.Item("autoDrawBool"), traitsui.Item("drawRequestButton"))) logGroup = traitsui.HGroup(traitsui.Item("logBool"), traitsui.Item("logFile", visible_when="logBool"), label="Logging", show_border=True) actionsGroup = traitsui.VGroup(traitsui.Item("fittingStatus", style="readonly"), logGroup, buttons, label="Fit Actions", show_border=True) traits_view = traitsui.View( traitsui.VGroup(generalGroup, variablesGroup, derivedGroup, actionsGroup)) def __init__(self, **traitsDict): super(Fit, self).__init__(**traitsDict) self.startX = 0 self.startY = 0 def _set_xs(self, xs): self.xs = xs def _set_ys(self, ys): self.ys = ys def _set_zs(self, zs): self.zs = zs def _fittingStatus_default(self): return self.notFittedForCurrentStatus def _getInitialValues(self): """returns ordered list of initial values from variables List """ return [_.initialValue for _ in self.variablesList] def _getCalculatedValues(self): """returns ordered list of initial values from variables List """ return [_.calculatedValue for _ in self.variablesList] def _log_fit(self): if self.logFile == "": logger.warning("no log file defined. Will not log") return if not os.path.exists(self.logFile): variables = [_.name for _ in self.variablesList] calculated = [_.name for _ in self.calculatedParametersList] times = ["datetime", "epoch seconds"] info = ["img file name"] columnNames = times + info + variables + calculated with open(self.logFile, 'a+') as logFile: writer = csv.writer(logFile) writer.writerow(columnNames) #column names already exist so... variables = [_.calculatedValue for _ in self.variablesList] calculated = [_.value for _ in self.calculatedParametersList] now = time.time() #epoch seconds timeTuple = time.localtime(now) date = time.strftime("%Y-%m-%dT%H:%M:%S", timeTuple) times = [date, now] info = [self.imageInspectorReference.selectedFile] data = times + info + variables + calculated with open(self.logFile, 'a+') as logFile: writer = csv.writer(logFile) writer.writerow(data) def _intelligentInitialValues(self): """If possible we can auto set the initial parameters to intelligent guesses user can always overwrite them """ self._setInitialValues(self._getIntelligentInitialValues()) def _get_subSpaceArrays(self): """returns the arrays of the selected sub space. If subspace is not activated then returns the full arrays""" if self.fitSubSpace: xs = self.xs[self.startX:self.endX] ys = self.ys[self.startY:self.endY] logger.debug("xs array sliced length %s " % (xs.shape)) logger.debug("ys array sliced length %s " % (ys.shape)) zs = self.zs[self.startY:self.endY, self.startX:self.endX] print zs print zs.shape logger.debug("zs sub space array %s,%s " % (zs.shape)) return xs, ys, zs else: return self.xs, self.ys, self.zs def _getIntelligentInitialValues(self): """If possible we can auto set the initial parameters to intelligent guesses user can always overwrite them """ logger.debug("Dummy function should not be called directly") return def fitFunc(self, data, *p): """Function that we are trying to fit to. """ logger.error("Dummy function should not be called directly") return def _setCalculatedValues(self, calculated): """updates calculated values with calculated argument """ c = 0 for variable in self.variablesList: variable.calculatedValue = calculated[c] c += 1 def _setCalculatedValuesErrors(self, covarianceMatrix): """given the covariance matrix returned by scipy optimize fit convert this into stdeviation errors for parameters list and updated the stdevError attribute of variables""" logger.debug("covariance matrix -> %s " % covarianceMatrix) parameterErrors = scipy.sqrt(scipy.diag(covarianceMatrix)) logger.debug("parameterErrors -> %s " % parameterErrors) c = 0 for variable in self.variablesList: variable.stdevError = parameterErrors[c] c += 1 def _setInitialValues(self, guesses): """updates calculated values with calculated argument """ c = 0 for variable in self.variablesList: variable.initialValue = guesses[c] c += 1 def deriveCalculatedParameters(self): """Wrapper for subclass definition of deriving calculated parameters can put more general calls in here""" if self.fitted: self._deriveCalculatedParameters() def _deriveCalculatedParameters(self): """Should be implemented by subclass. should update all variables in calculate parameters list""" logger.error("Should only be called by subclass") return def _fit_routine(self): """This function performs the fit in an appropriate thread and updates necessary values when the fit has been performed""" self.fitting = True if self.fitThread and self.fitThread.isAlive(): logger.warning( "Fitting is already running cannot kick off a new fit until it has finished!" ) return else: self.fitThread = FitThread() self.fitThread.fitReference = self self.fitThread.start() self.fittingStatus = self.currentlyFittingStatus def _perform_fit(self): """Perform the fit using scipy optimise curve fit. We must supply x and y as one argument and zs as anothger. in the form xs: 0 1 2 0 1 2 0 ys: 0 0 0 1 1 1 2 zs: 1 5 6 1 9 8 2 Hence the use of repeat and tile in positions and unravel for zs initially xs,ys is a linspace array and zs is a 2d image array """ if self.xs is None or self.ys is None or self.zs is None: logger.warning( "attempted to fit data but had no data inside the Fit object. set xs,ys,zs first" ) return ([], []) p0 = self._getInitialValues() if self.fitSubSpace: #fit only the sub space #create xs, ys and zs which are appropriate slices of the arrays xs, ys, zs = self._get_subSpaceArrays() positions = [scipy.tile(xs, len(ys)), scipy.repeat(ys, len(xs)) ] #for creating data necessary for gauss2D function params2D, cov2D = scipy.optimize.curve_fit(self.fitFunc, positions, scipy.ravel(zs), p0=p0) chi2 = scipy.sum( (scipy.ravel(zs) - self.fitFunc(positions, *params2D))**2 / self.fitFunc(positions, *params2D)) logger.debug("TEMPORARY ::: CHI^2 = %s " % chi2) else: #fit the whole array of data (slower) positions = [ scipy.tile(self.xs, len(self.ys)), scipy.repeat(self.ys, len(self.xs)) ] #for creating data necessary for gauss2D function #note that it is necessary to ravel zs as curve_fit expects a flattened array params2D, cov2D = scipy.optimize.curve_fit(self.fitFunc, positions, scipy.ravel(self.zs), p0=p0) return params2D, cov2D def _performFitButton_fired(self): self._fit_routine() def _getInitialParametersButton_fired(self): self._intelligentInitialValues() def _drawRequestButton_fired(self): """tells the imageInspector to try and draw this fit as an overlay contour plot""" self.imageInspectorReference.addFitPlot(self) def _getFitFuncData(self): """if data has been fitted, this returns the zs data for the ideal fitted function using the calculated paramters""" positions = [ scipy.tile(self.xs, len(self.ys)), scipy.repeat(self.ys, len(self.xs)) ] #for creating data necessary for gauss2D function zsravelled = self.fitFunc(positions, *self._getCalculatedValues()) return zsravelled.reshape(self.zs.shape)
class PowerReport(enable.Component): SAMPLE_INTERVAL = 1 # seconds v_list = traits.List plot_data = traits.Instance(chaco.ArrayPlotData) plot_container = traits.Instance(enable.Component) plots = traits.Dict traits_view = ui.View( ui.HGroup( ## ui.Item(name='v_list', editor=ui.EnumEditor(values=[str(v) for v in self.v_list])), ui.Item(name='plot_container', editor=enable.ComponentEditor(), show_label=False) ), kind='live' ) def __init__(self): super(PowerReport, self).__init__(title='Power') def update(self): # Check if the locally cached vehicle list has gotten stale. if len(self.v_list) != len(common.vehicles): self.v_list[:] = common.vehicles.values() self.v_list.sort() self.plot_data = self.make_plot_data(self.v_list) self.plots, self.plot_container = self.make_plots(self.plot_data) def make_plot_data(self, v_list): """Returns a chaco.ArrayPlotData containing the following: v_power -- A 2D array where each row is a vehicle (indexes match self.v_list), and each column is a time point. total_power - A 1D row array giving the network-wide power usage at each time point. Parameters: v_list -- a sequence of Vehicle objects, sorted by ID Does not support negative velocities. """ end_time = min(common.Sim.now(), common.config_manager.get_sim_end_time()) sample_times = numpy.arange(0, end_time+self.SAMPLE_INTERVAL, self.SAMPLE_INTERVAL) power_array = numpy.zeros( (len(v_list), len(sample_times)), dtype=numpy.float32) air_density = common.air_density wind_speed = common.wind_speed wind_angle = common.wind_direction # 0 is blowing FROM the East g = 9.80665 # m/s^2 PI_2 = math.pi/2 PI_3_2 = math.pi * 1.5 for v_idx, v in enumerate(v_list): masses = v.get_total_masses(sample_times) # The sample times may be out of the vehicle spline's valid range, # since the vehicle may not have been created at the beginning of # the simulation. v_start_time = v._spline.t[0] v_end_time = v._spline.t[-1] for idx, t in enumerate(sample_times): if t >= v_start_time: v_start_idx = idx # left index break for idx in xrange(len(sample_times)-1,-1,-1): if sample_times[idx] <= v_end_time: v_end_idx = idx+1 # right index break v_sample_times = sample_times[v_start_idx:v_end_idx] v_knots = v._spline.evaluate_sequence(v_sample_times) knots = [None] * len(sample_times) knots[v_start_idx:v_end_idx] = v_knots CdA = v.frontal_area * v.drag_coefficient path_idx = 0 path_sum = 0 loc = v._path[path_idx] last_elevation = loc.get_elevation(v_knots[0].pos) for sample_idx, (t, mass, knot) in enumerate(itertools.izip(sample_times, masses, knots)): if knot is None: power_array[v_idx, sample_idx] = 0 continue # Track where we are on the vehicle's path pos = knot.pos - path_sum if pos >= loc.length: path_sum += loc.length path_idx += 1 pos = knot.pos - path_sum loc = v._path[path_idx] # Power required to overcome rolling resistance. Ignores effect of # track slope and assumes that rolling resistance is constant # at different velocities. if v.rolling_coefficient: rolling_power = v.rolling_coefficient * g * mass * knot.vel # Force * velocity else: rolling_power = 0 # Rolling resistance not modelled # Power to accelerate / decelerate (change in kinetic energy) accel_power = mass * knot.accel * knot.vel # Power to overcome aero drag if wind_speed and knot.vel != 0: # No power use when stopped travel_angle = loc.get_direction(knot.pos - path_sum) # 0 is travelling TOWARDS the East incidence_angle = wind_angle - travel_angle if PI_2 <= incidence_angle <= PI_3_2: # tail wind vel = knot.vel - math.cos(incidence_angle)*wind_speed else: # head wind vel = knot.vel + math.cos(incidence_angle)*wind_speed else: vel = knot.vel aero_power = 0.5 * air_density * vel*vel*vel * CdA # Power from elevation changes (change in potential energy) elevation = loc.get_elevation(pos) delta_elevation = elevation - last_elevation elevation_power = g * delta_elevation last_elevation = elevation # Adjust power usages by efficiency net_power = accel_power + rolling_power + aero_power + elevation_power if net_power > 0: net_power /= v.powertrain_efficiency # low efficiency increases power required elif net_power < 0: net_power *= v.regenerative_braking_efficiency # low efficiency decreases power recovered power_array[v_idx, sample_idx] = net_power power_array = numpy.divide(power_array, 1000.0) # convert from Watts to KW positive_power = numpy.clip(power_array, 0, numpy.inf) positive_total_power = numpy.sum(positive_power, axis=0) negative_power = numpy.clip(power_array, -numpy.inf, 0) negative_total_power = numpy.sum(negative_power, axis=0) net_total_power = positive_total_power + negative_total_power energy_array = numpy.cumsum(power_array, axis=1) energy_array = numpy.divide(energy_array, 3600/self.SAMPLE_INTERVAL) # convert to KW-hours total_energy_array = numpy.sum(energy_array, axis=0) return chaco.ArrayPlotData( sample_times=chaco.ArrayDataSource(sample_times, sort_order="ascending"), positive_total_power=chaco.ArrayDataSource(positive_total_power), negative_total_power=chaco.ArrayDataSource(negative_total_power), net_total_power=chaco.ArrayDataSource(net_total_power), total_energy=chaco.ArrayDataSource(total_energy_array), v_power=power_array, positive_power=positive_power, negative_power=negative_power, energy_array=energy_array ) def make_plots(self, plot_data): """Create overlapping power and energy plots from the supplied plot_data. Parameters: plot_data -- A chaco.ArrayPlotData object. Expected to be created by self.make_plot_data. Return: A 2-tuple containing: - A dict containing plots, keyed by the plot name. - A chaco.OverlayPlotContainer containing the plots. """ times_mapper = chaco.LinearMapper(range=chaco.DataRange1D(plot_data.get_data('sample_times'), )) graph_colors = {'positive_total_power':'black', 'negative_total_power':'red', 'net_total_power':'purple', 'total_energy':'green'} plots = {} # Dict of all plots # Power graphs power_names = ['positive_total_power', 'negative_total_power', 'net_total_power'] power_data_range = chaco.DataRange1D(*[plot_data.get_data(name) for name in power_names]) power_mapper = chaco.LinearMapper(range=power_data_range) power_plots = {} for plot_name in power_names: plot = chaco.LinePlot(index=plot_data.get_data('sample_times'), value=plot_data.get_data(plot_name), index_mapper=times_mapper, value_mapper=power_mapper, border_visible=False, bg_color='transparent', line_style='solid', color=graph_colors[plot_name], line_width=2) power_plots[plot_name] = plot plots[plot_name] = plot # Energy graphs -- use a different value scale than power energy_plot_names = ['total_energy'] energy_data_range = chaco.DataRange1D(*[plot_data.get_data(name) for name in energy_plot_names]) energy_mapper = chaco.LinearMapper(range=energy_data_range) energy_plots = {} for plot_name in energy_plot_names: plot = chaco.LinePlot(index=plot_data.get_data('sample_times'), value=plot_data.get_data(plot_name), index_mapper=times_mapper, value_mapper=energy_mapper, border_visible=False, bg_color='transarent', line_style='solid', color=graph_colors[plot_name], line_width=2) energy_plots[plot_name] = plot plots[plot_name] = plot # Blank plot -- Holds the grid and axis, and acts as a placeholder when # no other graphs are activated. blank_values = chaco.ArrayDataSource(numpy.zeros( plot_data.get_data('sample_times').get_size() )) blank_plot = chaco.LinePlot(index=plot_data.get_data('sample_times'), value=blank_values, index_mapper=times_mapper, value_mapper=power_mapper, border_visible=True, bg_color='transparent', line_width=0) plots['blank_plot'] = plot times_axis = chaco.PlotAxis(orientation='bottom', title="Time (seconds)", mapper=times_mapper, component=blank_plot) power_axis = chaco.PlotAxis(orientation='left', title="Power (KW)", mapper=power_mapper, component=blank_plot) energy_axis = chaco.PlotAxis(orientation='right', title="Energy (KW-hrs)", mapper=energy_mapper, component=blank_plot) blank_plot.underlays.append(times_axis) blank_plot.underlays.append(power_axis) blank_plot.underlays.append(energy_axis) # Add zoom capability blank_plot.overlays.append(tools.ZoomTool(blank_plot, tool_mode='range', axis='index', always_on=True, drag_button='left')) plot_container = chaco.OverlayPlotContainer() for plot in power_plots.itervalues(): plot_container.add(plot) for plot in energy_plots.itervalues(): plot_container.add(plot) plot_container.add(blank_plot) plot_container.padding_left = 60 plot_container.padding_right = 60 plot_container.padding_top = 20 plot_container.padding_bottom = 50 # Legend legend = chaco.Legend(component=plot_container, padding=20, align="ur") legend.tools.append(tools.LegendTool(legend, drag_button="right")) legend.plots = {} legend.plots.update(power_plots) legend.plots.update(energy_plots) plot_container.overlays.append(legend) return plots, plot_container
class Parameter(traits.HasTraits): """represents a lmfit variable in a fit. E.g. the standard deviation in a gaussian fit""" parameter = traits.Instance(lmfit.Parameter) name = traits.Str initialValue = traits.Float calculatedValue = traits.Float vary = traits.Bool(True) minimumEnable = traits.Bool(False) minimum = traits.Float maximumEnable = traits.Bool(False) maximum = traits.Float stdevError = traits.Float def __init__(self, **traitsDict): super(Parameter, self).__init__(**traitsDict) self.parameter = lmfit.Parameter(name=self.name) def _initialValue_changed(self): self.parameter.set(value=self.initialValue) def _vary_changed(self): self.parameter.set(vary=self.vary) def _minimum_changed(self): if self.minimumEnable: self.parameter.set(min=self.minimum) def _maximum_changed(self): if self.maximumEnabled: self.parameter.set(max=self.maximum) traits_view = traitsui.View(traitsui.VGroup( traitsui.HGroup( traitsui.Item("vary", label="vary?", resizable=True), traitsui.Item("name", show_label=False, style="readonly", width=0.2, resizable=True), traitsui.Item("initialValue", label="initial", show_label=True, resizable=True), traitsui.Item("calculatedValue", label="calculated", show_label=True, format_str="%G", style="readonly", width=0.2, resizable=True), traitsui.Item("stdevError", show_label=False, format_str=u"\u00B1%G", style="readonly", resizable=True)), traitsui.HGroup( traitsui.Item("minimumEnable", label="min?", resizable=True), traitsui.Item("minimum", label="min", resizable=True, visible_when="minimumEnable"), traitsui.Item("maximumEnable", label="max?", resizable=True), traitsui.Item("maximum", label="max", resizable=True, visible_when="maximumEnable"))), kind="subpanel")
class Fit(traits.HasTraits): name = traits.Str(desc="name of fit") function = traits.Str(desc="function we are fitting with all parameters") variablesList = traits.List(Parameter) calculatedParametersList = traits.List(CalculatedParameter) xs = None # will be a scipy array ys = None # will be a scipy array zs = None # will be a scipy array performFitButton = traits.Button("Perform Fit") getInitialParametersButton = traits.Button("Guess Initial Values") usePreviousFitValuesButton = traits.Button("Use Previous Fit") drawRequestButton = traits.Button("Draw Fit") setSizeButton = traits.Button("Set Initial Size") chooseVariablesButtons = traits.Button("choose logged variables") logLibrarianButton = traits.Button("librarian") logLastFitButton = traits.Button("log current fit") removeLastFitButton = traits.Button("remove last fit") autoFitBool = traits.Bool( False, desc= "Automatically perform this Fit with current settings whenever a new image is loaded" ) autoGuessBool = traits.Bool( False, desc= "Whenever a fit is completed replace the guess values with the calculated values (useful for increasing speed of the next fit)" ) autoDrawBool = traits.Bool( False, desc= "Once a fit is complete update the drawing of the fit or draw the fit for the first time" ) autoSizeBool = traits.Bool( False, desc= "If TOF variable is read from latest XML and is equal to 0.11ms (or time set in Physics) then it will automatically update the physics sizex and sizey with the Sigma x and sigma y from the gaussian fit" ) logBool = traits.Bool( False, desc="Log the calculated and fitted values with a timestamp") logName = traits.String( desc="name of the scan - will be used in the folder name") logDirectory = os.path.join("\\\\ursa", "AQOGroupFolder", "Experiment Humphry", "Data", "eagleLogs") latestSequence = os.path.join("\\\\ursa", "AQOGroupFolder", "Experiment Humphry", "Experiment Control And Software", "currentSequence", "latestSequence.xml") logFile = traits.File(desc="file path of logFile") logAnalyserBool = traits.Bool( False, desc="only use log analyser script when True") logAnalysers = [ ] #list containing full paths to each logAnalyser file to run logAnalyserDisplayString = traits.String( desc= "comma separated read only string that is a list of all logAnalyser python scripts to run. Use button to choose files" ) logAnalyserSelectButton = traits.Button("sel. analyser", image='@icons:function_node', style="toolbar") xmlLogVariables = [] imageInspectorReference = None #will be a reference to the image inspector fitting = traits.Bool(False) #true when performing fit fitted = traits.Bool( False) #true when current data displayed has been fitted fitSubSpace = traits.Bool( False) #true when current data displayed has been fitted startX = traits.Int startY = traits.Int endX = traits.Int endY = traits.Int fittingStatus = traits.Str() fitThread = None fitTimeLimit = traits.Float( 10.0, desc= "Time limit in seconds for fitting function. Only has an effect when fitTimeLimitBool is True" ) fitTimeLimitBool = traits.Bool( True, desc= "If True then fitting functions will be limited to time limit defined by fitTimeLimit " ) physics = traits.Instance( physicsProperties.physicsProperties.PhysicsProperties) #status strings notFittedForCurrentStatus = "Not Fitted for Current Image" fittedForCurrentImageStatus = "Fit Complete for Current Image" currentlyFittingStatus = "Currently Fitting..." failedFitStatus = "Failed to finish fit. See logger" timeExceededStatus = "Fit exceeded user time limit" lmfitModel = traits.Instance( lmfit.Model ) #reference to the lmfit model must be initialised in subclass mostRecentModelResult = None # updated to the most recent ModelResult object from lmfit when a fit thread is performed fitSubSpaceGroup = traitsui.VGroup( traitsui.Item("fitSubSpace", label="Fit Sub Space", resizable=True), traitsui.VGroup(traitsui.HGroup( traitsui.Item("startX", resizable=True), traitsui.Item("startY", resizable=True)), traitsui.HGroup(traitsui.Item("endX", resizable=True), traitsui.Item("endY", resizable=True)), visible_when="fitSubSpace"), label="Fit Sub Space", show_border=True) generalGroup = traitsui.VGroup(traitsui.Item("name", label="Fit Name", style="readonly", resizable=True), traitsui.Item("function", label="Fit Function", style="readonly", resizable=True), fitSubSpaceGroup, label="Fit", show_border=True) variablesGroup = traitsui.VGroup(traitsui.Item( "variablesList", editor=traitsui.ListEditor(style="custom"), show_label=False, resizable=True), show_border=True, label="parameters") derivedGroup = traitsui.VGroup(traitsui.Item( "calculatedParametersList", editor=traitsui.ListEditor(style="custom"), show_label=False, resizable=True), show_border=True, label="derived values") buttons = traitsui.VGroup( traitsui.HGroup( traitsui.Item("autoFitBool", label="Auto fit?", resizable=True), traitsui.Item("performFitButton", show_label=False, resizable=True)), traitsui.HGroup( traitsui.Item("autoGuessBool", label="Auto guess?", resizable=True), traitsui.Item("getInitialParametersButton", show_label=False, resizable=True)), traitsui.HGroup( traitsui.Item("autoDrawBool", label="Auto draw?", resizable=True), traitsui.Item("drawRequestButton", show_label=False, resizable=True)), traitsui.HGroup( traitsui.Item("autoSizeBool", label="Auto size?", resizable=True), traitsui.Item("setSizeButton", show_label=False, resizable=True)), traitsui.HGroup( traitsui.Item("usePreviousFitValuesButton", show_label=False, resizable=True))) logGroup = traitsui.VGroup(traitsui.HGroup( traitsui.Item("logBool", resizable=True), traitsui.Item("chooseVariablesButtons", show_label=False, resizable=True)), traitsui.HGroup( traitsui.Item("logName", resizable=True)), traitsui.HGroup( traitsui.Item("removeLastFitButton", show_label=False, resizable=True), traitsui.Item("logLastFitButton", show_label=False, resizable=True)), traitsui.HGroup( traitsui.Item("logAnalyserBool", label="analyser?", resizable=True), traitsui.Item("logAnalyserDisplayString", show_label=False, style="readonly", resizable=True), traitsui.Item("logAnalyserSelectButton", show_label=False, resizable=True)), label="Logging", show_border=True) actionsGroup = traitsui.VGroup(traitsui.Item("fittingStatus", style="readonly", resizable=True), logGroup, buttons, label="Fit Actions", show_border=True) traits_view = traitsui.View(traitsui.VGroup(generalGroup, variablesGroup, derivedGroup, actionsGroup), kind="subpanel") def __init__(self, **traitsDict): super(Fit, self).__init__(**traitsDict) self.startX = 0 self.startY = 0 self.lmfitModel = lmfit.Model(self.fitFunc) def _set_xs(self, xs): self.xs = xs def _set_ys(self, ys): self.ys = ys def _set_zs(self, zs): self.zs = zs def _fittingStatus_default(self): return self.notFittedForCurrentStatus def _getInitialValues(self): """returns ordered list of initial values from variables List """ return [_.initialValue for _ in self.variablesList] def _getParameters(self): """creates an lmfit parameters object based on the user input in variablesList """ return lmfit.Parameters( {_.name: _.parameter for _ in self.variablesList}) def _getCalculatedValues(self): """returns ordered list of fitted values from variables List """ return [_.calculatedValue for _ in self.variablesList] def _intelligentInitialValues(self): """If possible we can auto set the initial parameters to intelligent guesses user can always overwrite them """ self._setInitialValues(self._getIntelligentInitialValues()) def _get_subSpaceArrays(self): """returns the arrays of the selected sub space. If subspace is not activated then returns the full arrays""" if self.fitSubSpace: xs = self.xs[self.startX:self.endX] ys = self.ys[self.startY:self.endY] logger.info("xs array sliced length %s " % (xs.shape)) logger.info("ys array sliced length %s " % (ys.shape)) zs = self.zs[self.startY:self.endY, self.startX:self.endX] logger.info("zs sub space array %s,%s " % (zs.shape)) return xs, ys, zs else: return self.xs, self.ys, self.zs def _getIntelligentInitialValues(self): """If possible we can auto set the initial parameters to intelligent guesses user can always overwrite them """ logger.debug("Dummy function should not be called directly") return #in python this should be a pass statement. I.e. user has to overwrite this def fitFunc(self, data, *p): """Function that we are trying to fit to. """ logger.error("Dummy function should not be called directly") return #in python this should be a pass statement. I.e. user has to overwrite this def _setCalculatedValues(self, modelFitResult): """updates calculated values with calculated argument """ parametersResult = modelFitResult.params for variable in self.variablesList: variable.calculatedValue = parametersResult[variable.name].value def _setCalculatedValuesErrors(self, modelFitResult): """given the covariance matrix returned by scipy optimize fit convert this into stdeviation errors for parameters list and updated the stdevError attribute of variables""" parametersResult = modelFitResult.params for variable in self.variablesList: variable.stdevError = parametersResult[variable.name].stderr def _setInitialValues(self, guesses): """updates calculated values with calculated argument """ c = 0 for variable in self.variablesList: variable.initialValue = guesses[c] c += 1 def deriveCalculatedParameters(self): """Wrapper for subclass definition of deriving calculated parameters can put more general calls in here""" if self.fitted: self._deriveCalculatedParameters() def _deriveCalculatedParameters(self): """Should be implemented by subclass. should update all variables in calculate parameters list""" logger.error("Should only be called by subclass") return def _fit_routine(self): """This function performs the fit in an appropriate thread and updates necessary values when the fit has been performed""" self.fitting = True if self.fitThread and self.fitThread.isAlive(): logger.warning( "Fitting is already running. You should wait till this fit has timed out before a new thread is started...." ) #logger.warning("I will start a new fitting thread but your previous thread may finish at some undetermined time. you probably had bad starting conditions :( !") return self.fitThread = FitThread() #new fitting thread self.fitThread.fitReference = self self.fitThread.isCurrentFitThread = True # user can create multiple fit threads on a particular fit but only the latest one will have an effect in the GUI self.fitThread.start() self.fittingStatus = self.currentlyFittingStatus def _perform_fit(self): """Perform the fit using scipy optimise curve fit. We must supply x and y as one argument and zs as anothger. in the form xs: 0 1 2 0 1 2 0 ys: 0 0 0 1 1 1 2 zs: 1 5 6 1 9 8 2 Hence the use of repeat and tile in positions and unravel for zs initially xs,ys is a linspace array and zs is a 2d image array """ if self.xs is None or self.ys is None or self.zs is None: logger.warning( "attempted to fit data but had no data inside the Fit object. set xs,ys,zs first" ) return ([], []) params = self._getParameters() if self.fitSubSpace: #fit only the sub space #create xs, ys and zs which are appropriate slices of the arrays xs, ys, zs = self._get_subSpaceArrays() else: #fit the whole array of data (slower) xs, ys, zs = self.xs, self.ys, self.zs positions = scipy.array([ scipy.tile(xs, len(ys)), scipy.repeat(ys, len(xs)) ]) #for creating data necessary for gauss2D function if self.fitTimeLimitBool: modelFitResult = self.lmfitModel.fit(scipy.ravel(zs), positions=positions, params=params, iter_cb=self.getFitCallback( time.time())) else: #no iter callback modelFitResult = self.lmfitModel.fit(scipy.ravel(zs), positions=positions, params=params) return modelFitResult def getFitCallback(self, startTime): """returns the callback function that is called at every iteration of fit to check if it has been running too long""" def fitCallback(params, iter, resid, *args, **kws): """check the time and compare to start time """ if time.time() - startTime > self.fitTimeLimit: raise FitException("Fit time exceeded user limit") return fitCallback def _performFitButton_fired(self): self._fit_routine() def _getInitialParametersButton_fired(self): self._intelligentInitialValues() def _drawRequestButton_fired(self): """tells the imageInspector to try and draw this fit as an overlay contour plot""" self.imageInspectorReference.addFitPlot(self) def _setSizeButton_fired(self): """use the sigmaX and sigmaY from the current fit to overwrite the inTrapSizeX and inTrapSizeY parameters in the Physics Instance""" self.physics.inTrapSizeX = abs(self.sigmax.calculatedValue) self.physics.inTrapSizeY = abs(self.sigmay.calculatedValue) def _getFitFuncData(self): """if data has been fitted, this returns the zs data for the ideal fitted function using the calculated paramters""" positions = [ scipy.tile(self.xs, len(self.ys)), scipy.repeat(self.ys, len(self.xs)) ] #for creating data necessary for gauss2D function zsravelled = self.fitFunc(positions, *self._getCalculatedValues()) return zsravelled.reshape(self.zs.shape) def _logAnalyserSelectButton_fired(self): """open a fast file editor for selecting many files """ fileDialog = FileDialog(action="open files") fileDialog.open() if fileDialog.return_code == pyface.constant.OK: self.logAnalysers = fileDialog.paths logger.info("selected log analysers: %s " % self.logAnalysers) self.logAnalyserDisplayString = str( [os.path.split(path)[1] for path in self.logAnalysers]) def runSingleAnalyser(self, module): """runs the logAnalyser module calling the run function and returns the columnNames and values as a list""" exec("import logAnalysers.%s as currentAnalyser" % module) reload( currentAnalyser ) #in case it has changed..#could make this only when user requests #now the array also contains the raw image as this may be different to zs if you are using a processor if hasattr(self.imageInspectorReference, "rawImage"): rawImage = self.imageInspectorReference.rawImage else: rawImage = None return currentAnalyser.run([self.xs, self.ys, self.zs, rawImage], self.physics.variables, self.variablesList, self.calculatedParametersList) def runAnalyser(self): """ if logAnalyserBool is true we perform runAnalyser at the end of _log_fit runAnalyser checks that logAnalyser exists and is a python script with a valid run()function it then performs the run method and passes to the run function: -the image data as a numpy array -the xml variables dictionary -the fitted paramaters -the derived values""" for logAnalyser in self.logAnalysers: if not os.path.isfile(logAnalyser): logger.error( "attempted to runAnalyser but could not find the logAnalyser File: %s" % logAnalyser) return #these will contain the final column names and values finalColumns = [] finalValues = [] #iterate over each selected logAnalyser get the column names and values and add them to the master lists for logAnalyser in self.logAnalysers: directory, module = os.path.split(logAnalyser) module, ext = os.path.splitext(module) if ext != ".py": logger.error("file was not a python module. %s" % logAnalyser) else: columns, values = self.runSingleAnalyser(module) finalColumns.extend(columns) finalValues.extend(values) return finalColumns, finalValues def mostRecentModelFitReport(self): """returns the lmfit fit report of the most recent lmfit model results object""" if self.mostRecentModelResult is not None: return lmfit.fit_report(self.mostRecentModelResult) + "\n\n" else: return "No fit performed" def getCalculatedParameters(self): """useful for print returns tuple list of calculated parameter name and value """ return [(_.name, _.value) for _ in self.calculatedParametersList] def _log_fit(self): if self.logName == "": logger.warning("no log file defined. Will not log") return #generate folders if they don't exist logFolder = os.path.join(self.logDirectory, self.logName) if not os.path.isdir(logFolder): logger.info("creating a new log folder %s" % logFolder) os.mkdir(logFolder) imagesFolder = os.path.join(logFolder, "images") if not os.path.isdir(imagesFolder): logger.info("creating a new images Folder %s" % imagesFolder) os.mkdir(imagesFolder) commentsFile = os.path.join(logFolder, "comments.txt") if not os.path.exists(commentsFile): logger.info("creating a comments file %s" % commentsFile) open(commentsFile, "a+").close() #create a comments file in every folder! firstSequenceCopy = os.path.join(logFolder, "copyOfInitialSequence.ctr") if not os.path.exists(firstSequenceCopy): logger.info("creating a copy of the first sequence %s -> %s" % (self.latestSequence, firstSequenceCopy)) shutil.copy(self.latestSequence, firstSequenceCopy) if self.imageInspectorReference.model.imageMode == "process raw image": #if we are using a processor, save the details of the processor used to the log folder processorParamtersFile = os.path.join(logFolder, "processorOptions.txt") processorPythonScript = os.path.join(logFolder, "usedProcessor.py") #TODO! if not os.path.exists(processorParamtersFile): with open(processorParamtersFile, "a+") as processorParamsFile: string = str(self.imageInspectorReference.model. chosenProcessor) + "\n" string += str(self.imageInspectorReference.model.processor. optionsDict) processorParamsFile.write(string) logger.debug("finished all checks on log folder") #copy current image try: shutil.copy(self.imageInspectorReference.selectedFile, imagesFolder) except IOError as e: logger.error("Could not copy image. Got IOError: %s " % e.message) except Exception as e: logger.error("Could not copy image. Got %s: %s " % (type(e), e.message)) raise e logger.info("copying current image") self.logFile = os.path.join(logFolder, self.logName + ".csv") #analyser logic if self.logAnalyserBool: #run the analyser script as requested logger.info( "log analyser bool enabled... will attempt to run analyser script" ) analyserResult = self.runAnalyser() logger.info("analyser result = %s " % list(analyserResult)) if analyserResult is None: analyserColumnNames = [] analyserValues = [] #analyser failed. continue as if nothing happened else: analyserColumnNames, analyserValues = analyserResult else: #no analyser enabled analyserColumnNames = [] analyserValues = [] if not os.path.exists(self.logFile): variables = [_.name for _ in self.variablesList] calculated = [_.name for _ in self.calculatedParametersList] times = ["datetime", "epoch seconds"] info = ["img file name"] xmlVariables = self.xmlLogVariables columnNames = times + info + variables + calculated + xmlVariables + analyserColumnNames with open( self.logFile, 'ab+' ) as logFile: # note use of binary file so that windows doesn't write too many /r writer = csv.writer(logFile) writer.writerow(columnNames) #column names already exist so... logger.debug("copying current image") variables = [_.calculatedValue for _ in self.variablesList] calculated = [_.value for _ in self.calculatedParametersList] now = time.time() #epoch seconds timeTuple = time.localtime(now) date = time.strftime("%Y-%m-%dT%H:%M:%S", timeTuple) times = [date, now] info = [self.imageInspectorReference.selectedFile] xmlVariables = [ self.physics.variables[varName] for varName in self.xmlLogVariables ] data = times + info + variables + calculated + xmlVariables + analyserValues with open(self.logFile, 'ab+') as logFile: writer = csv.writer(logFile) writer.writerow(data) def _logLastFitButton_fired(self): """logs the fit. User can use this for non automated logging. i.e. log particular fits""" self._log_fit() def _removeLastFitButton_fired(self): """removes the last line in the log file """ logFolder = os.path.join(self.logDirectory, self.logName) self.logFile = os.path.join(logFolder, self.logName + ".csv") if self.logFile == "": logger.warning("no log file defined. Will not log") return if not os.path.exists(self.logFile): logger.error( "cant remove a line from a log file that doesn't exist") with open(self.logFile, 'r') as logFile: lines = logFile.readlines() with open(self.logFile, 'wb') as logFile: logFile.writelines(lines[:-1]) def saveLastFit(self): """saves result of last fit to a txt/csv file. This can be useful for live analysis or for generating sequences based on result of last fit""" try: with open( self.imageInspectorReference.cameraModel + "-" + self.physics.species + "-" + "lastFit.csv", "wb") as lastFitFile: writer = csv.writer(lastFitFile) writer.writerow(["time", time.time()]) for variable in self.variablesList: writer.writerow([variable.name, variable.calculatedValue]) for variable in self.calculatedParametersList: writer.writerow([variable.name, variable.value]) except Exception as e: logger.error("failed to save last fit to text file. message %s " % e.message) def _chooseVariablesButtons_fired(self): self.xmlLogVariables = self.chooseVariables() def _usePreviousFitValuesButton_fired(self): """update the guess initial values with the value from the last fit """ logger.info( "use previous fit values button fired. loading previous initial values" ) self._setInitialValues(self._getCalculatedValues()) def chooseVariables(self): """Opens a dialog asking user to select columns from a data File that has been selected. THese are then returned as a string suitable for Y cols input""" columns = self.physics.variables.keys() columns.sort() values = zip(range(0, len(columns)), columns) checklist_group = traitsui.Group( '10', # insert vertical space traitsui.Label('Select the additional variables you wish to log'), traitsui.UItem('columns', style='custom', editor=traitsui.CheckListEditor(values=values, cols=6)), traitsui.UItem('selectAllButton')) traits_view = traitsui.View(checklist_group, title='CheckListEditor', buttons=['OK'], resizable=True, kind='livemodal') col = ColumnEditor(numberOfColumns=len(columns)) try: col.columns = [ columns.index(varName) for varName in self.xmlLogVariables ] except Exception as e: logger.error( "couldn't selected correct variable names. Returning empty selection" ) logger.error("%s " % e.message) col.columns = [] col.edit_traits(view=traits_view) logger.debug("value of columns selected = %s ", col.columns) logger.debug("value of columns selected = %s ", [columns[i] for i in col.columns]) return [columns[i] for i in col.columns] def _logLibrarianButton_fired(self): """opens log librarian for current folder in logName box. """ logFolder = os.path.join(self.logDirectory, self.logName) if not os.path.isdir(logFolder): logger.error( "cant open librarian on a log that doesn't exist.... Could not find %s" % logFolder) return librarian = plotObjects.logLibrarian.Librarian(logFolder=logFolder) librarian.edit_traits()