def field_changed(changed): "Handle event where selected field changed" new = changed["new"] old = changed["old"] widgets.value_range.default = True cv = coverage.get(params.current_casedir) if cv is None: slider.disabled = True plot_field() return slider.disabled = False if new != old: min_ts, max_ts, step_ts, valid = get_timestepping(new) cbc_log( 20, "In field-changed: Time-step range=%d-%d" % (min_ts, max_ts)) widgets.slider.min = -1e16 widgets.slider.max = 1e16 widgets.slider.min = min_ts widgets.slider.max = max_ts widgets.slider.step = step_ts #value_range.value="-" #value_range.value = None if not valid: widgets.slider.value = widgets.slider.value plot_field()
def update(self, t, timestep, cache, triggered_or_finalized): """Iterate through the triggered_or_finalized-list of fields, and save the fields with Field.params.save == True""" for field in triggered_or_finalized: #print name, cache[name] if field.params.save: cbc_log(20, "Saving field %s" % field.name) self._action_save(field, cache[field.name], timestep, t) if timestep % self.flush_frequency == 0: self._flush_data() self._timer.completed("PP: flush data")
def setup_available_fields(): num_all = np.count_nonzero( [c.value == "all" for c in widgets.batch_params.children]) af = widgets.available_fields af.options = [] current = af.value if num_all == 0: for k in fields: if k == "time": continue af.options += fields[k] af.options = list(sorted(af.options)) else: for k in fields: if "float" in k: af.options += fields[k] if current not in af.options: if len(af.options) > 0: af.value = available_fields.options[0] cbc_log(20, "In setup_available_fields: af.options=" + str(af.options)) cbc_log(20, "In setup_available_fields: af.value=" + str(af.value))
def _action_save(self, field, data, timestep, t): "Apply the 'save' action to computed field data." field_name = field.name # Create save folder first time self._create_savedir(field_name) # Collect metadata shared between data types metadata = { 'timestep': timestep, 'time': t, } # Rename Functions to get the right name in file # (NB! This has the obvious side effect!) # TODO: We don't need to cache a distinct Function # object like we do for plotting, or? if isinstance(data, Function): data.rename(field_name, "Function produced by cbcpost.") # Get list of file formats save_as = _get_save_formats(field, data) # Notify user if self.rewrite_mesh has been set without mattering if field.params["rewrite_mesh"]: if not "xdmf" in save_as: cbc_log( 30, "rewrite_mesh flag has no effect for field {}".format( field_name)) # Write data to file for each filetype for saveformat in save_as: # Write data to file depending on type if saveformat == 'pvd': metadata[saveformat] = self._update_pvd_file( field_name, saveformat, data, timestep, t) elif saveformat == 'xdmf': metadata[saveformat] = self._update_xdmf_file( field_name, saveformat, data, timestep, t, field.params["rewrite_mesh"]) elif saveformat == 'xml': metadata[saveformat] = self._update_xml_file( field_name, saveformat, data, timestep, t) elif saveformat == 'xml.gz': metadata[saveformat] = self._update_xml_gz_file( field_name, saveformat, data, timestep, t) elif saveformat == 'txt': metadata[saveformat] = self._update_txt_file( field_name, saveformat, data, timestep, t) elif saveformat == 'hdf5': metadata[saveformat] = self._update_hdf5_file( field_name, saveformat, data, timestep, t) elif saveformat == 'shelve': metadata[saveformat] = self._update_shelve_file( field_name, saveformat, data, timestep, t) else: error("Unknown save format %s." % (saveformat, )) self._timer.completed("PP: save %s %s" % (field_name, saveformat)) # Write new data to metadata file self._update_metadata_file(field_name, data, t, timestep, save_as, metadata) self._timer.completed("PP: update metadata") self._fill_playlog(field, timestep, save_as) self._timer.completed("PP: update playlog")
def value_range_changed(change): "Handle value range changed" vr = widgets.value_range cbc_log(20, "In value range changed: change=" + str(change)) cbc_log(20, "In value range changed: default=" + str(vr.default)) cbc_log(20, "In value range changed: visible=" + str(vr.visible)) cbc_log(20, "In value range changed: value=" + str(vr.value)) r = vr.max - vr.min cbc_log(20, "In value range changed: range=" + str(r)) min, max = vr.value if r < 1e-12 or (abs(min - vr.min) / r < 1e-4 and abs(max - vr.max) / r < 1e-4): vr.default = True else: if r < 1e-12: vr.default = True else: vr.default = False cbc_log(20, "In value range changed (after): default=" + str(vr.default)) plot_field()
def plot_field(): "Plot field. This method is called on every scene change in the gui" compute_current_value() type = current_value.type if type == "function": cbc_log(20, "Plotting function field") widgets.value_range.visible = True widgets.edge_cb.visible = True widgets.slider.visible = True widgets.play_pause_button.visible = True #widgets.plot_type.visible = False #widgets.log_scale.visible = False # Bug if these are added on first render, without function plot, # they are still shown. Therefore, adding them here c = list(containers[2][1].children) if widgets.value_range not in c: c.append(widgets.value_range) if widgets.edge_cb not in c: c.append(widgets.edge_cb) containers[2][1].children = tuple(c) #widgets.time.visible = True if current_value.key not in fields.timedependent_function: widgets.slider.disabled = True widgets.play_pause_button.disabled = True else: widgets.slider.disabled = False widgets.play_pause_button.disabled = False plot_function_field() elif type == "matplotlib": cbc_log(20, "Plotting matplotlib field") widgets.value_range.visible = False widgets.slider.visible = False widgets.play_pause_button.visible = False widgets.edge_cb.visible = False """ c = list(containers[2][1].children) if not widgets.plot_type in c: c.append(widgets.plot_type) if not widgets.log_scale in c: c.append(widgets.log_scale) containers[2][1].children = tuple(c) if widgets.plot_type.value == "plot": widgets.log_scale.visible = False else: widgets.log_scale.visible = True widgets.plot_type.visible = True """ #if current_value.xlabel == "Time": # widgets.time.visible = False plot_matplotlib_field() elif type == "float": cbc_log(20, "Plotting float field") widgets.value_range.visible = False widgets.edge_cb.visible = False widgets.slider.visible = False widgets.play_pause_button.visible = False #widgets.plot_type.visible = False #widgets.log_scale.visible = False #widgets.time.visible = True plot_float_field() elif type == "pandas": cbc_log(20, "Plotting pandas field") widgets.value_range.visible = False widgets.edge_cb.visible = False widgets.slider.visible = False widgets.play_pause_button.visible = False #widgets.plot_type.visible = False #widgets.log_scale.visible = False #widgets.time.visible = True plot_pandas_field() else: raise RuntimeError("Unable to recognize field type %s" % type)
def get(self, name, relative_timestep=0, compute=True, finalize=False): """Get the value of a named field at a particular relative_timestep. The relative_timestep is relative to now. Values are computed at first request and cached. """ cbc_log( 20, "Getting: %s, %d (compute=%s, finalize=%s)" % (name, relative_timestep, compute, finalize)) # Check cache c = self._cache[relative_timestep] data = c.get(name, "N/A") # Check if field has been finalized, and if so, # return finalized value if name in self._finalized and data == "N/A": if compute: cbc_warning( "Field %s has already been finalized. Will not call compute on field." % name) return self._finalized[name] # Are we attempting to get value from before update was started? # Use constant extrapolation if allowed. if abs(relative_timestep) > self._update_all_count and data == "N/A": if self._extrapolate: cbc_log( 20, "Extrapolating %s from %d to %d" % (name, relative_timestep, -self._update_all_count)) data = self.get(name, -self._update_all_count, compute, finalize) c[name] = data else: raise RuntimeError( "Unable to get data from before update was started. \ (%s, relative_timestep: %d, update_all_count: %d)" % (name, relative_timestep, self._update_all_count)) # Cache miss? if data == "N/A": field = self._fields[name] if relative_timestep == 0: # Ensure before_first_compute is always called once initially if self._compute_counts[field.name] == 0: init_data = field.before_first_compute(self.get) self._timer.completed("PP: before first compute %s" % name) if init_data is not None: cbc_warning("Did not expect a return value from \ %s.before_first_compute." % field.__class__) # Compute value if name in self._solution: data = self._solution[name]() self._timer.completed("PP: call solution %s" % name) else: if compute: data = field.compute(self.get) self._timer.completed("PP: compute %s" % name) """ if finalize: finalized_data = field.after_last_compute(self.get) if finalized_data not in [None, "N/A"]: data = finalized_data self._finalized[name] = data self._timer.completed("PP: finalize %s" %name) """ self._compute_counts[field.name] += 1 # Copy functions to avoid storing references to the same function objects at each relative_timestep # NB! In other cases we assume that the fields return a new object for every compute! # Check first if we actually will cache this object by looking at 'time to keep' in the plan if self._plan[0][name] > 0: if isinstance(data, Function): # TODO: Use function pooling to avoid costly allocations? data = data.copy(deepcopy=True) # Cache it! #c[name] = data else: # Cannot compute missing value from previous relative_timestep, # dependency handling must have failed raise DependencyException(name, relative_timestep=relative_timestep) if finalize: field = self._fields[name] finalized_data = field.after_last_compute(self.get) if finalized_data not in [None, "N/A"]: data = finalized_data self._finalized[name] = data self._timer.completed("PP: finalize %s" % name) c[name] = data return data
def add_field(self, field, exists_reaction="error"): "Add field to postprocessor." assert isinstance(field, Field) # Note: If field already exists, replace anyway to overwrite params, this # typically happens when a fields has been created implicitly by dependencies. # This is a bit unsafe though, the user might add a field twice with different parameters... # Check that at least the same name is not used for different field classes: # UPDATE: Keep it safe, and raise error if field exists. if field.name in self._fields: s = "Field with name %s already been added to postprocessor." % field.name if exists_reaction == "replace": cbc_log(30, s + " Replacing.") elif exists_reaction == "ignore": cbc_log(30, s + " Ignoring.") return else: raise AssertionError(s) #assert field.name not in self._fields, "Field with name %s already been added to postprocessor." %field.name #assert type(field) == type(self._fields.get(field.name,field)) #if field.name in self._fields: # cbc_warning("Field with name %s already been added to postprocessor. Ignoring." %field.name) # return # Add fields explicitly specified by field self.add_fields(field.add_fields(), "ignore") # Analyze dependencies of field through source inspection deps = field.explicit_dependencies() if deps is None: deps = find_dependencies(field) for dep in deps: if dep[0] not in self._fields and dep[0] not in builtin_fields: raise DependencyException(fieldname=field.name, dependency=dep[0]) # Build full dependency list full_deps = [] existing_full_deps = set() for dep in deps: depname, ts = dep for fdep in self._full_dependencies[depname]: # Sort out correct (relative) timestep of dependency fdepname, fts = fdep fts += ts fdep = (fdepname, fts) if fdep not in existing_full_deps: existing_full_deps.add(fdep) full_deps.append(fdep) existing_full_deps.add(dep) full_deps.append(dep) # Add field to internal data structures self._fields[field.name] = field self._dependencies[field.name] = deps self._full_dependencies[field.name] = full_deps self._insert_in_sorted_list(field.name) cbc_log(20, "Added field: %s" % field.name) # Returning the field object is useful for testing return field