class WTDescFromWTG(Component): """Create a wt_desc from a .wtg WAsP file""" # Inputs filename = Str(iotype='in', desc='The .wtg file name') # Outputs wt_desc = VarTree(GenericWindTurbinePowerCurveVT(), iotype='out', desc='The wind turbine power curve') def __init__(self, filename=None): super(WTDescFromWTG, self).__init__() if filename is not None: self.filename = filename self.execute() def execute(self): # Reading the .wtg file wtg = WTG(self.filename) # Filling up the VT self.wt_desc.power_curve = wtg.data[:, :2] self.wt_desc.c_t_curve = vstack([wtg.data[:, 0], wtg.data[:, 2]]).T self.wt_desc.cut_in_wind_speed = wtg.data[0, 0] self.wt_desc.cut_out_wind_speed = wtg.data[-1, 0] self.wt_desc.air_density = wtg.density self.wt_desc.rotor_diameter = wtg.rotor_diameter self.wt_desc.power_rating = self.wt_desc.power_curve[:, 1].max() self.wt_desc.hub_height = wtg.hub_height self.wt_desc.test_consistency()
class PlantFromWWF(Component): """Create a Plant information from a .wwf WAsP file""" # Inputs filename = Str(iotype='in', desc='The .wwf file name') wt_desc = VarTree(GenericWindTurbinePowerCurveVT(), iotype='in', desc='The wind turbine power curve') # Outputs wt_layout = VarTree(GenericWindFarmTurbineLayout(), iotype='out', desc='wind turbine properties and layout') wind_rose_array = Array( iotype='out', units='m/s', desc='Windrose array [wind_directions, frequency, weibull_A, weibull_k]' ) def execute(self): # Reading the .wwf file wwf = WWF(self.filename) self.wt_layout.wt_list.append(self.wt_desc) # self.wt_layout.wt_wind_roses.frequency_array = self.wt_layout.configure_single() for wt, wr in self.wwf.windroses.iteritems(): self.wt_layout.wt_positions[i, :] = self.wwf.data[wt][:2] self.wt_layout.wt_wind_roses.append(wr) i += 1 self.wt_layout.configure_single() # For practical reason we also output the first wind rose array outside # the wt_layout self.wind_rose_array = self.wt_layout.wt_wind_roses[0]
class PlantFromWWH(Component): """Create a Plant information from a .wwh WAsP file""" # Inputs filename = Str(iotype='in', desc='The .wwh file name') # Outputs wt_layout = VarTree(GenericWindFarmTurbineLayout(), iotype='out', desc='wind turbine properties and layout') #wind_rose_array = Array(iotype='out', units='m/s', # desc='Windrose array [wind_directions, frequency, weibull_A, weibull_k]') wind_rose_vt = VarTree(WeibullWindRoseVT(), iotype='out', desc='wind turbine Weibull wind rose') def __init__(self, filename=None): """ The constructor that can take the wwh filename as optional parameter. :param filename: wwh file name [optional] :return: self """ super(PlantFromWWH, self).__init__() if filename is not None: self.filename = filename self.execute() def execute(self): # Reading the .wwf file wwh = WWH(self.filename) iWT = 0 for wt, data in wwh.wind_turbines.iteritems(): turbine = wwh.turbine_descriptions[data['type']] self.wt_layout.add_wt( WTPC(name='wt_' + wt, position=data['position'][:2], wind_rose=GenericWindRoseVT( weibull_array=data['wind_rose']), power_curve=turbine['data'][:, :2], power_rating=max(turbine['data'][:, 1]), c_t_curve=turbine['data'][:, [0, 2]], cut_in_wind_speed=turbine['data'][0, 0], cut_out_wind_speed=turbine['data'][-1, 0], air_density=turbine['density'], rotor_diameter=turbine['rotor_diameter'], hub_height=data['position'][2])) self.wind_rose_vt.add( 'wt_' + wt, VarTree((WeibullWindRoseVT(data['wind_rose']))))
class VariableTree(Container): """A tree of variables having the same input or output sense.""" _iotype = Str('') implements(IVariableTree) def __init__(self, iotype=''): self._parent_ref = None super(VariableTree, self).__init__() self._iotype = iotype # Check for nested VariableTrees in the class definition. for name, obj in self.__class__.__dict__.items(): if isinstance(obj, VariableTree): raise TypeError('Nested VariableTrees are not supported,' ' please wrap %s.%s in a VarTree' % (self.__class__.__name__, name)) self.install_callbacks() # register callbacks for our class traits for name, trait in self.class_traits().items(): if not name.startswith('_'): self.on_trait_change(self._trait_modified, name) @property def _parent(self): """ Return dereferenced weakref to parent. """ return None if self._parent_ref is None else self._parent_ref() @_parent.setter def _parent(self, value): """ Set weakref to parent. """ self._parent_ref = None if value is None else weakref.ref(value) def __getstate__(self): """ Return state after dereferencing weakref to parent. """ state = super(VariableTree, self).__getstate__() if self._parent_ref is not None: state['_parent_ref'] = self._parent_ref() return state def __setstate__(self, state): """ Set state and set weakref to parent. """ super(VariableTree, self).__setstate__(state) if self._parent_ref is not None: self._parent_ref = weakref.ref(self._parent_ref) @property def iotype(self): if not self._iotype and isinstance(self.parent, VariableTree): self._iotype = self.parent.iotype return self._iotype @rbac(('owner', 'user')) def cpath_updated(self): if self.parent: if isinstance(self.parent, VariableTree): self._iotype = self.parent.iotype else: t = self.parent.trait(self.name) if t and t.iotype: self._iotype = t.iotype super(VariableTree, self).cpath_updated() @rbac(('owner', 'user')) def get_metadata(self, traitpath, metaname=None): if metaname == 'iotype': return self.iotype elif metaname is None: meta = super(VariableTree, self).get_metadata(traitpath, metaname) meta['iotype'] = self.iotype return meta else: return super(VariableTree, self).get_metadata(traitpath, metaname) def copy(self): """Returns a deep copy of this VariableTree, without deepcopying its parent. Also installs necessary trait callbacks. """ cp = super(VariableTree, self).copy() cp.install_callbacks() return cp def __deepcopy__(self, memo): id_self = id(self) if id_self in memo: return memo[id_self] cp = super(VariableTree, self).__deepcopy__(memo) cp.install_callbacks() return cp def install_callbacks(self): """Install trait callbacks on deep-copied VariableTree.""" self.on_trait_change(self._iotype_modified, '_iotype') # _alltraits() is missing some traits after a deepcopy, so use the # union of _alltraits() and everything in self.__dict__ allset = set(self._alltraits().keys()) allset.update(self.__dict__.keys()) for name in allset: if name not in ('trait_added', 'trait_modified') \ and not name.startswith('_') and hasattr(self, name): self.on_trait_change(self._trait_modified, name) obj = getattr(self, name) if isinstance(obj, VariableTree) and obj is not self.parent: obj.install_callbacks() def add(self, name, obj): if not (IVariable.providedBy(obj) or isinstance(obj, VarTree)): msg = "a VariableTree may only contain Variables or VarTrees" self.raise_exception(msg, TypeError) return super(VariableTree, self).add(name, obj) def add_trait(self, name, trait, refresh=True): super(VariableTree, self).add_trait(name, trait, refresh) if not name.startswith('_'): self.on_trait_change(self._trait_modified, name) def remove_trait(self, name): trait = self.get_trait(name) # remove the callback if trait: self.on_trait_change(self._trait_modified, name, remove=True) super(VariableTree, self).remove_trait(name) def list_vars(self): """Return a list of Variables in this VariableTree.""" return [k for k in self.__dict__.keys() if not k.startswith('_')] def _iotype_modified(self, obj, name, old, new): for v in self.__dict__.values(): if isinstance(v, (VariableTree, VarTree)) and v is not self.parent: v._iotype = new def _trait_modified(self, obj, name, old, new): # handle weird traits side-effect from hasattr call if name == 'trait_added': return if isinstance(new, VariableTree): obj = getattr(self, name) obj.parent = self obj._iotype = self._iotype if self._iotype == 'in': p = self path = [name] while isinstance(p, VariableTree): vt = p p = p.parent path.append(vt.name) # notify parent Component that this VariableTree has been modified if p is not None: t = p.trait(vt.name) if t and t.iotype == 'in': # we need to pass the full pathname of the child that was # actually modified up to the parent component, and we can't # modify the arglist of _input_trait_modified, so instead # call _input_updated explicitly p._input_updated(vt.name, fullpath='.'.join(path[::-1])) def get_iotype(self, name): """Return the iotype of the Variable with the given name""" if self.get_trait(name) is None: self.raise_exception("'%s' not found" % name) return self.iotype def _items(self, visited, recurse=False, **metadata): """Return an iterator that returns a list of tuples of the form (rel_pathname, obj) for each trait of this VariableTree that matches the given metadata. If recurse is True, also iterate through all child Containers of each Container found. """ if id(self) not in visited: visited.add(id(self)) if 'iotype' in metadata: meta_io = metadata['iotype'] matches_io = False if type(meta_io) is FunctionType: if meta_io(self.iotype): matches_io = True elif meta_io == self.iotype: matches_io = True if matches_io: newdict = metadata.copy() del newdict['iotype'] else: matches_io = True newdict = metadata if matches_io: for name in self._alltraits(**newdict): if name.startswith('_'): continue obj = getattr(self, name) yield (name, obj) if recurse and is_instance(obj, VariableTree) and \ id(obj) not in visited: for chname, child in obj._items( visited, recurse, **metadata): yield ('.'.join((name, chname)), child) @rbac(('owner', 'user')) def get_req_default(self, vt_required=None): """Returns a list of all inputs that are required but still have their default value. """ req = [] if vt_required: req_test = [True, False, None] else: req_test = [True] for name, trait in self.traits(type=not_event).items(): obj = getattr(self, name) if obj is self.parent: continue if is_instance(obj, VariableTree): req.extend([ '.'.join((self.name, n)) for n in obj.get_req_default(vt_required) ]) elif trait.required in req_test: try: trait = trait.trait_type except: unset = (obj == trait.default) else: unset = (obj == trait.default_value) if not isinstance(unset, bool): try: unset = unset.all() except: pass if unset: req.append('.'.join((self.name, name))) return req def get_attributes(self, io_only=True, indent=0, parent=''): """ Get attributes for this variable tree. Used by the GUI. io_only: bool Set to True if we only want to populate the input and output fields of the attributes dictionary. indent: int Recursion level (for collapsing tables). parent: str ID name of parent table line. valid: str Validity state of the parent table.""" attrs = {} attrs['type'] = type(self).__name__ self_io = self.iotype # Connection information found in parent comp's parent assy if not self.parent or not self.parent._parent or \ isinstance(self.parent, VariableTree): connected = [] else: graph = self.parent._parent._depgraph if self_io == 'in': connected = graph.get_boundary_inputs(connected=True) else: connected = graph.get_boundary_outputs(connected=True) variables = [] for name in self.list_vars(): trait = self.get_trait(name) meta = self.get_metadata(name) value = getattr(self, name) ttype = trait.trait_type # Each variable type provides its own basic attributes attr, slot_attr = ttype.get_attribute(name, value, trait, meta) # if this var is the top element of a variable tree, add 'vt' attribute if attr.get('ttype') == 'vartree': vartable = self.get(name) if isinstance(vartable, VariableTree): attr['vt'] = 'vt' # Support for expand/collapse attr['indent'] = indent attr['id'] = '%s.%s' % (parent, name) if parent: attr['parent'] = parent attr['connected'] = '' if name in connected: connections = self.parent._depgraph.connections_to(name) if self_io == 'in': # there can be only one connection to an input attr['connected'] = str([src for src, dst in connections]) else: attr['connected'] = str([dst for src, dst in connections]) variables.append(attr) # For variables trees only: recursively add the inputs and outputs # into this variable list if 'vt' in attr: vt_attrs = vartable.get_attributes(io_only, indent=indent + 1, parent=attr['id']) if self_io == 'in': variables += vt_attrs['Inputs'] else: variables += vt_attrs['Outputs'] if self_io == 'in': attrs['Inputs'] = variables else: attrs['Outputs'] = variables return attrs
class VariableTree(Container): """A tree of variables having the same input or output sense.""" _iotype = Str('') implements(IVariableTree) def __init__(self, iotype=''): self._parent_ref = None super(VariableTree, self).__init__() self._iotype = iotype # Check for nested VariableTrees in the class definition. for name, obj in self.__class__.__dict__.items(): if isinstance(obj, VariableTree): raise TypeError('Nested VariableTrees are not supported,' ' please wrap %s.%s in a VarTree' % (self.__class__.__name__, name)) self.install_callbacks() # register callbacks for our class traits for name, trait in self.class_traits().items(): if not name.startswith('_'): self.on_trait_change(self._trait_modified, name) @property def _parent(self): """ Return dereferenced weakref to parent. """ return None if self._parent_ref is None else self._parent_ref() @_parent.setter def _parent(self, value): """ Set weakref to parent. """ self._parent_ref = None if value is None else weakref.ref(value) def __getstate__(self): """ Return state after dereferencing weakref to parent. """ state = super(VariableTree, self).__getstate__() if self._parent_ref is not None: state['_parent_ref'] = self._parent_ref() return state def __setstate__(self, state): """ Set state and set weakref to parent. """ super(VariableTree, self).__setstate__(state) if self._parent_ref is not None: self._parent_ref = weakref.ref(self._parent_ref) @property def iotype(self): if not self._iotype and isinstance(self.parent, VariableTree): self._iotype = self.parent.iotype return self._iotype @rbac(('owner', 'user')) def cpath_updated(self): if self.parent: if isinstance(self.parent, VariableTree): self._iotype = self.parent.iotype else: t = self.parent.trait(self.name) if t and t.iotype: self._iotype = t.iotype super(VariableTree, self).cpath_updated() @rbac(('owner', 'user')) def get_metadata(self, traitpath, metaname=None): if metaname == 'iotype': return self.iotype elif metaname is None: meta = super(VariableTree, self).get_metadata(traitpath, metaname) meta['iotype'] = self.iotype return meta else: return super(VariableTree, self).get_metadata(traitpath, metaname) def copy(self): """Returns a deep copy of this VariableTree, without deepcopying its parent. Also installs necessary trait callbacks. """ cp = super(VariableTree, self).copy() cp.install_callbacks() return cp def __deepcopy__(self, memo): id_self = id(self) if id_self in memo: return memo[id_self] cp = super(VariableTree, self).__deepcopy__(memo) cp.install_callbacks() return cp def install_callbacks(self): """Install trait callbacks on deep-copied VariableTree.""" self.on_trait_change(self._iotype_modified, '_iotype') # _alltraits() is missing some traits after a deepcopy, so use the # union of _alltraits() and everything in self.__dict__ allset = set(self._alltraits().keys()) allset.update(self.__dict__.keys()) for name in allset: if name not in ('trait_added', 'trait_modified') \ and not name.startswith('_') and hasattr(self, name): self.on_trait_change(self._trait_modified, name) obj = getattr(self, name) if isinstance(obj, VariableTree) and obj is not self.parent: obj.install_callbacks() def add(self, name, obj): if not (IVariable.providedBy(obj) or isinstance(obj, VarTree)): msg = "a VariableTree may only contain Variables or VarTrees" self.raise_exception(msg, TypeError) return super(VariableTree, self).add(name, obj) def add_trait(self, name, trait, refresh=True): super(VariableTree, self).add_trait(name, trait, refresh) if not name.startswith('_'): self.on_trait_change(self._trait_modified, name) def remove_trait(self, name): trait = self.get_trait(name) # remove the callback if trait: self.on_trait_change(self._trait_modified, name, remove=True) super(VariableTree, self).remove_trait(name) def list_vars(self): """Return a list of Variables in this VariableTree.""" return [k for k in self.__dict__.keys() if not k.startswith('_')] def _iotype_modified(self, obj, name, old, new): for v in self.__dict__.values(): if isinstance(v, (VariableTree, VarTree)) and v is not self.parent: v._iotype = new def _trait_modified(self, obj, name, old, new): # handle weird traits side-effect from hasattr call if name == 'trait_added': return if isinstance(new, VariableTree): obj = getattr(self, name) obj.parent = self obj._iotype = self._iotype if self._iotype == 'in': p = self path = [name] while isinstance(p, VariableTree): vt = p p = p.parent path.append(vt.name) # notify parent Component that this VariableTree has been modified if p is not None: t = p.trait(vt.name) if t and t.iotype == 'in': # we need to pass the full pathname of the child that was # actually modified up to the parent component, and we can't # modify the arglist of _input_trait_modified, so instead # call _input_updated explicitly p._input_updated(vt.name, fullpath='.'.join(path[::-1])) def get_iotype(self, name): """Return the iotype of the Variable with the given name""" if self.get_trait(name) is None: self.raise_exception("'%s' not found" % name) return self.iotype def _items(self, visited, recurse=False, **metadata): """Return an iterator that returns a list of tuples of the form (rel_pathname, obj) for each trait of this VariableTree that matches the given metadata. If recurse is True, also iterate through all child Containers of each Container found. """ if id(self) not in visited: visited.add(id(self)) if 'iotype' in metadata: meta_io = metadata['iotype'] matches_io = False if type(meta_io) is FunctionType: if meta_io(self.iotype): matches_io = True elif meta_io == self.iotype: matches_io = True if matches_io: newdict = metadata.copy() del newdict['iotype'] else: matches_io = True newdict = metadata if matches_io: for name in self._alltraits(**newdict): if name.startswith('_'): continue obj = getattr(self, name) yield (name, obj) if recurse and is_instance(obj, VariableTree) and \ id(obj) not in visited: for chname, child in obj._items(visited, recurse, **metadata): yield ('.'.join((name, chname)), child) @rbac(('owner', 'user')) def get_req_default(self, vt_required=None): """Returns a list of all inputs that are required but still have their default value. """ req = [] if vt_required: req_test = [True, False, None] else: req_test = [True] for name, trait in self.traits(type=not_event).items(): obj = getattr(self, name) if obj is self.parent: continue if is_instance(obj, VariableTree): req.extend(['.'.join((self.name, n)) for n in obj.get_req_default(vt_required)]) elif trait.required in req_test: try: trait = trait.trait_type except: unset = (obj == trait.default) else: unset = (obj == trait.default_value) if not isinstance(unset, bool): try: unset = unset.all() except: pass if unset: req.append('.'.join((self.name, name))) return req def list_all_vars(self): """Return a list of all variables in this VarTree (recursive).""" vnames = [] for name, obj in self.__dict__.items(): if name.startswith('_'): continue if isinstance(obj, VariableTree): vnames.extend(['.'.join((self.name,n)) for n in obj.list_all_vars()]) else: vnames.append('.'.join((self.name, name))) return vnames def get_flattened_size(self): """Return the size of a flattened float array containing all values in the vartree that are flattenable to float arrays. Any values not flattenable to float arrays will raise a NoFlatError. """ size = 0 for key in self.list_vars(): size += flattened_size(key, getattr(self, key), scope=self) return size def get_flattened_index(self, name): """Return the slice within the flattened array of the current vartree that is occupied by the named subvar. """ raise NotImplementedError('get_flattened_index not implemented for VarTrees yet') # FIXME