Hi everyone, I made a sizable update to the Clump class, allowing far more flexibility in the type of output you get from the clump finder. In case anyone is interested, here's the commit log. Britton Author: britton Date: Sat Jan 17 12:43:53 2009 New Revision: 1126 URL: http://yt.spacepope.org/changeset/1126 Log: Added clump_info attribute to Clump objects. clump_info is an list of dictionaries, each with two entries: "quantity" and "format". The quantity entry contains a string representing the function to be called to get some Clump quantity or quantities. The format entry contains another string that controls the format that the quantity is to be written out. Both are used with eval statemets by the new Clump info writing method, write_info. The method, write_info, is called by the write_clumps and write_clump_hierarchy routines. This allows the user to add their own quantities to the list to be printed out by write_clumps and write_clump_hierarchy. This is done by the Clump method add_info_item, which takes arguments quantity and format to be added to the clump_info list. After adding the entry to the clump_info list, the method is called for each of the clumps children in a recursive fashion so that all children in the hierarchy have the same clump_info list. The Clump __init__ function now also accepts the keyword, clump_info, so that clump_info traits can be passed down at instantiation. This means that add_info_item can be called either before or after the clump finding is done. If clump objects are instantiated with no entries in clump_info, the method, set_default_clump_info is called to add the standard info items that were printed out by the old writing functions. This means that by running the clump finder the way it has always been run, you will get the same output as before. Check out this method for examples of proper calls to add_info_item. The clump_info list can be cleared with the clear_clump_info method. Clump objects now also contain a method called "pass_down", which allows the user to pass down any sort of command that is to be executed by all clumps in the hierarchy. The argument to pass_down is given as a string to be executed with eval. For example, this allows the user to define clump characteristics for each clump that depend on external data not known before clump finding. One specific example would be a clump info item that is the distance from the center of mass of the master clump. Finally, for backwards compatibility, the original clump writing functions have been kept around as write_old_clumps and write_old_clump_hierarchy. Modified: trunk/yt/lagos/Clump.py Modified: trunk/yt/lagos/Clump.py ============================================================================== --- trunk/yt/lagos/Clump.py (original) +++ trunk/yt/lagos/Clump.py Sat Jan 17 12:43:53 2009 @@ -22,13 +22,13 @@ along with this program. If not, see http://www.gnu.org/licenses/. """ - from yt.lagos import * import numpy as na +import copy class Clump(object): children = None - def __init__(self, data, parent, field, cached_fields = None, function=None): + def __init__(self, data, parent, field, cached_fields = None, function=None, clump_info=None): self.parent = parent self.data = data self.field = field @@ -36,6 +36,14 @@ self.max = self.data[field].max() self.cached_fields = cached_fields + # List containing characteristics about clumps that are to be written + # out by the write routines. + if clump_info is None: + self.set_default_clump_info() + else: + # Clump info will act the same if add_info_item is called before or after clump finding. + self.clump_info = copy.deepcopy(clump_info) + # Function determining whether a clump is valid and should be kept. self.default_function = 'self.data.quantities["IsBound"](truncate=True,include_thermal_energy=True)
1.0' if function is None: @@ -46,14 +54,53 @@ # Return value of validity function, saved so it does not have to be calculated again. self.function_value = None
- def _isValid(self): - "Perform user specified function to determine if child clumps should be kept." - - # Only call function is it has not been already. - if self.function_value is None: - self.function_value = eval(self.function) + def add_info_item(self,quantity,format): + "Adds an entry to clump_info list and tells children to do the same." - return self.function_value + self.clump_info.append({'quantity':quantity, 'format':format}) + if self.children is None: return + for child in self.children: + child.add_info_item(quantity,format) + + def set_default_clump_info(self): + "Defines default entries in the clump_info array." + + # add_info_item is recursive so this function does not need to be. + self.clump_info = [] + + # Number of cells. + self.add_info_item('self.data["CellMassMsun"].size','"Cells: %d" % value') + # Gas mass in solar masses. + self.add_info_item('self.data["CellMassMsun"].sum()','"Mass: %e Msolar" % value') + # Volume-weighted Jeans mass. + self.add_info_item('self.data.quantities["WeightedAverageQuantity"]("JeansMassMsun","CellVolume")', + '"Jeans Mass (vol-weighted): %.6e Msolar" % value') + # Mass-weighted Jeans mass. + self.add_info_item('self.data.quantities["WeightedAverageQuantity"]("JeansMassMsun","CellMassMsun")', + '"Jeans Mass (mass-weighted): %.6e Msolar" % value') + # Max level. + self.add_info_item('self.data["GridLevel"].max()','"Max grid level: %d" % value') + # Minimum number density. + self.add_info_item('self.data["NumberDensity"].min()','"Min number density: %.6e cm^-3" % value') + # Maximum number density. + self.add_info_item('self.data["NumberDensity"].max()','"Max number density: %.6e cm^-3" % value') + + def clear_clump_info(self): + "Clears the clump_info array and passes the instruction to its children." + + self.clump_info = [] + if self.children is None: return + for child in self.children: + child.clear_clump_info() + + def write_info(self,level,f_ptr): + "Writes information for clump using the list of items in clump_info." + + for item in self.clump_info: + value = eval(item['quantity']) + output = eval(item['format']) + f_ptr.write("%s%s" % ('\t'*level,output)) + f_ptr.write("\n") def find_children(self, min, max = None): if self.children is not None: @@ -65,22 +112,41 @@ for cid in contour_info: new_clump = self.data.extract_region(contour_info[cid]) self.children.append(Clump(new_clump, self, self.field, - self.cached_fields,function=self.function)) + self.cached_fields,function=self.function, + clump_info=self.clump_info)) + + def pass_down(self,operation): + "Performs an operation on a clump with an exec and passes the instruction down to clump children." + + exec(operation) + + for child in self.children: + child.pass_down(operation) + + def _isValid(self): + "Perform user specified function to determine if child clumps should be kept." + + # Only call function if it has not been already. + if self.function_value is None: + self.function_value = eval(self.function) + + return self.function_value def __reduce__(self): return (_reconstruct_clump, (self.parent, self.field, self.min, self.max, - self.function_value, self.children, self.data, self.function)) + self.function_value, self.children, self.data, self.clump_info, self.function)) def __getitem__(self,request): return self.data[request] -def _reconstruct_clump(parent, field, mi, ma, function_value, children, data, + +def _reconstruct_clump(parent, field, mi, ma, function_value, children, data, clump_info, function=None): obj = object.__new__(Clump) if iterable(parent): parent = parent[1] if children is None: children = [] - obj.parent, obj.field, obj.min, obj.max, obj.function_value, \ - obj.children, obj.function = parent, field, mi, ma, function_value, children, function + obj.parent, obj.field, obj.min, obj.max, obj.function_value, obj.children, obj.clump_info, obj.function = \ + parent, field, mi, ma, function_value, children, clump_info, function # Now we override, because the parent/child relationship seems a bit # unreliable in the unpickling for child in children: child.parent = obj @@ -117,12 +183,11 @@ print "%d of %d children survived, erasing children." % (len(these_children),len(clump.children)) clump.children = [] - def write_clump_hierarchy(clump,level,f_ptr): for q in range(level): f_ptr.write("\t") f_ptr.write("Clump at level %d:\n" % level) - write_clump_info(clump,level,f_ptr) + clump.write_info(level,f_ptr) f_ptr.write("\n") f_ptr.flush() if ((clump.children is not None) and (len(clump.children) > 0)): @@ -132,7 +197,30 @@ def write_clumps(clump,level,f_ptr): if ((clump.children is None) or (len(clump.children) == 0)): f_ptr.write("%sClump:\n" % ("\t"*level)) - write_clump_info(clump,level,f_ptr) + clump.write_info(level,f_ptr) + f_ptr.write("\n") + f_ptr.flush() + if ((clump.children is not None) and (len(clump.children) > 0)): + for child in clump.children: + write_clumps(child,0,f_ptr) + +# Old clump info writing routines. +def write_old_clump_hierarchy(clump,level,f_ptr): + for q in range(level): + f_ptr.write("\t") + f_ptr.write("Clump at level %d:\n" % level) + clump.write_info(level,f_ptr) + write_old_clump_info(clump,level,f_ptr) + f_ptr.write("\n") + f_ptr.flush() + if ((clump.children is not None) and (len(clump.children) > 0)): + for child in clump.children: + write_clump_hierarchy(child,(level+1),f_ptr) + +def write_old_clumps(clump,level,f_ptr): + if ((clump.children is None) or (len(clump.children) == 0)): + f_ptr.write("%sClump:\n" % ("\t"*level)) + write_old_clump_info(clump,level,f_ptr) f_ptr.write("\n") f_ptr.flush() if ((clump.children is not None) and (len(clump.children) > 0)): @@ -151,7 +239,7 @@ """ -def write_clump_info(clump,level,f_ptr): +def write_old_clump_info(clump,level,f_ptr): fmt_dict = {'tl': "\t" * level} fmt_dict['num_cells'] = clump.data["CellMassMsun"].size, fmt_dict['total_mass'] = clump.data["CellMassMsun"].sum() _______________________________________________ Yt-svn mailing list Yt-svn@lists.spacepope.org http://lists.spacepope.org/listinfo.cgi/yt-svn-spacepope.org