class Core(Collection): _tablename = 'cores' @classmethod def connect(cls, backend): cls._table = backend.ctable(cls.tablename()) #useful notes -- all keys (depths) are converted to millimeter units before #being used to reference a Sample value. Keys are still displayed to the #user in their selected unit, as those are actually pulled from the sample def __init__(self, name='New Core', plans=[], properties={}): self.name = name self.runs = set(plans) self.runs.add('input') self.properties = Sample() self.properties.update(properties) self.loaded = False super(Core, self).__init__([]) def _dbkey(self, key): try: key = key.rescale('mm') except AttributeError: key = key return float(key) def _unitkey(self, depth): try: return float(depth.rescale('mm').magnitude) except AttributeError: return float(depth) @classmethod def makesample(cls, data): instance = Sample() instance.update(cls._table.loaddictformat(data)) return instance def saveitem(self, key, value): return (self._dbkey(key), self._table.formatsavedict(value)) def new_computation(self, cplan): """ Add a new computation plan to this core, and return a VirtualCore with the requested plan set. """ run = Run(cplan) self.runs.add(run.name) vc = VirtualCore(self, run.name) #convenience for this specific case -- the run is still in-creation, #so we need to keep the object around until it's done. vc.partial_run = run return vc @property def vruns(self): return [run for run in self.runs if run != 'input'] def virtualize(self): """ Returns a full set of virtual cores applicable to this Core This is currently returned as a list, sorted by run name. """ if len(self.runs) == 1: #return input as its own critter iff it's the only plan in this core return [VirtualCore(self, 'input')] else: cores = [] for run in sorted(self.runs): if run == 'input': continue cores.append(VirtualCore(self, run)) return cores def __getitem__(self, key): if key == 'all': print "Warning: use of 'all' key is deprecated. Use core.properties instead" return self.properties return self._data[self._unitkey(key)] def __setitem__(self, depth, sample): if depth == 'all': print "Warning: use of 'all' key is deprecated. Use core.properties instead" self.properties = sample return super(Core, self).__setitem__(self._unitkey(depth), sample) try: self.runs.update(sample.keys()) except AttributeError: #not actually a run, just some background pass def add(self, sample): sample['input']['core'] = self.name self[sample['input']['depth']] = sample def forcesample(self, depth): try: return self[depth] except KeyError: s = Sample(exp_data={'depth': depth}) self.add(s) return s def force_load(self): #not my favorite hack, but wevs. if not self.loaded: for sample in self: pass def __iter__(self): #if I'm getting all the keys, I'm going to want the values too, so #I might as well pull everything. Whee! if self.loaded: for key in self._data: yield key else: for key, value in self._table.iter_core_samples(self): if key == 'all': #if we've got a core that used to have data in 'all', we want #to put that data nicely in properties for great justice on #load (should only happen on first load...) sam = self.makesample(value) #since it's not a "normal" sample anymore, it doesn't need #depth and core, and life will be easier without them... try: del sam['input']['depth'] del sam['input']['core'] except KeyError: pass self.properties = sam continue #not actually part of our iteration, lulz numeric = UncertainQuantity(key, 'mm') self._data[self._unitkey(numeric)] = self.makesample(value) yield numeric self.loaded = True
def makesample(cls, data): instance = Sample() instance.update(cls._table.loaddictformat(data)) return instance