importloggingimportpickleimportreimportuuidfromcopyimportdeepcopyfromdatetimeimportdatetimeimportnumpyasnpfromopenpnm.utilsimportSettingsAttr,Workspacews=Workspace()logger=logging.getLogger(__name__)__all__=['Project',]classProjectSettings(SettingsAttr):r""" uuid : str A universally unique identifier for the object to keep things straight """uuid=''original_uuid=''@propertydefname(self):returnself._name@name.setterdefname(self,name):name=ws._validate_name(name)forvinlist(ws.values()):ifv.settingsisself:ws[name]=ws.pop(v.settings.name)self._name=name
[docs]classProject(list):r""" This class provides a container for all OpenPNM objects in a given simulation. A simulation is defined as a Network and all of it's associated objects. When instantiating a Network, a Project can be passed as an argument, but if not given one is created. When instantiating any other object either a Network or a Project can be supplied. In the former case, the Network's Project is retrieved and used. The end result is that all objects are stored in a specific Project. The Project to which any object belongs can be retrieved with ``obj.project``. Conversely, printing a Project displays a list of all objects it contains. Moreover, all Projects are registered with the Workspace. Since there can be only instance of the Workspace it is possible to view all open Projects by printing the Workspace. See Also -------- Workspace """def__init__(self,*args,**kwargs):self.settings=ProjectSettings()self.settings['name']=kwargs.pop('name',None)self.settings['uuid']=str(uuid.uuid4())self.settings['original_uuid']=self.settings['uuid']super().__init__(*args,**kwargs)ws[self.settings['name']]=selfdef__getitem__(self,key):try:returnsuper().__getitem__(key)exceptTypeError:ifisinstance(key,str):# Enable dict-style lookup if key is a stringforiteminself:ifitem.name==key:returnitemraiseKeyError(key)
[docs]defcopy(self,name=None):r""" Creates a deep copy of the current project A deep copy means that new, unique versions of all the objects are created but with identical data and properties. Parameters ---------- name : str The name to give to the new project. If not supplied, a name is automatically generated. Returns ------- proj : list A new Project object containing copies of all objects Notes ----- Because they are new objects, they are given a new uuid (``obj.settings['uuid']``), but the uuid of the original object is also stored (``obj.settings['original_uuid']``) for reference. """name=ws._validate_name(name)proj=deepcopy(self)foriteminproj:item.settings['uuid']=str(uuid.uuid4())proj.settings['uuid']=str(uuid.uuid4())proj.settings['name']=namews[name]=projreturnproj
def_set_name(self,name):self.settings['name']=namedef_get_name(self):returnself.settings['name']name=property(fget=_get_name,fset=_set_name)def_validate_name(self,name):ifnameinself.names:raiseException('Another object is already named '+name)foriteminself:forkeyinitem.keys():ifkey.split('.')[1]==name:raiseException('A property/label is already named '+name)def_generate_name(self,name=''):ifnamein[None,'']:name='obj_01'# Give basic name, then let rest of func fix itwarn=Trueifname.endswith('_?'):name=name.replace('_?','_01')warn=Falseifnameinself.names:# If proposed name is taken, increment itproposed_name=nameifnotre.search(r'_\d+$',name):# If name does not end with _##name=name+'_01'prefix,count=name.rsplit('_',1)n=[0]foriteminself:ifitem.name.startswith(prefix+'_'):n.append(int(item.name.split(prefix+'_')[1]))name=prefix+'_'+str(max(n)+1).zfill(2)ifwarn:logger.warn(f'{proposed_name} is already taken, using {name} instead')self._validate_name(name)returnname@propertydefnames(self):names=[i.nameforiinself]returnnames@propertydefnetwork(self):foriteminself:if('throat.conns'initem.keys())or('pore.coords'initem.keys()):returnitem@propertydefphases(self):fromopenpnm.phaseimportPhasephases=[]foriteminself:ifisinstance(item,Phase):phases.append(item)returnphases@propertydefalgorithms(self):fromopenpnm.algorithmsimportAlgorithmalgs=[]foriteminself:ifisinstance(item,Algorithm):algs.append(item)returnalgs@propertydefworkspace(self):returnwsdef_get_locations(self,label):r""" Find locations indicated by the given label regardless of which object it is defined on Parameters ---------- label : str The label whose locations are sought, such as 'pore.left' Returns ------- locations : ndarray A boolean array with ``True`` values indicating which locations have the given label Notes ----- The returns the first instance of ``label`` that it finds """foriteminself:try:returnitem[label]exceptKeyError:passraiseKeyError(label)def__str__(self):# pragma: no coverhr='―'*78s='═'*78+'\n's+='Object Name : Object Class and ID'+'\n's+=hr+'\n'foriteminself:s+=item.__repr__()+'\n's+=hrreturns