def _bcremove(self, mesh, name): if parallel_enable.enabled(): boundaryconditionIPC.ipcbcmenu.Delete(mesh=mesh,name=name) else: meshcontext = ooflib.engine.mesh.meshes[mesh] meshcontext.rmBdyConditionByName(name) switchboard.notify("mesh changed", ooflib.engine.mesh.meshes[mesh])
def _skeleton_copy(menuitem, skeleton, name): if parallel_enable.enabled(): from ooflib.engine.IO import skeletonIPC skeletonIPC.smenu.Copy(skeleton=skeleton, name=name) return # skeleton is a colon separated string oldskelpath = labeltree.makePath(skeleton) oldskelcontext = skeletoncontext.skeletonContexts[skeleton] if name is automatic.automatic: nm = skeletoncontext.skeletonContexts.uniqueName(skeleton) else: nm = name orig = oldskelcontext.getObject() newskel = orig.properCopy(fresh=True) for e in oldskelcontext.edgeboundaries.values(): newskel.mapBoundary(e, orig, local=None) for p in oldskelcontext.pointboundaries.values(): newskel.mapBoundary(p, orig, local=None) msname = oldskelpath[0] # "add" calls the SkeletonContext constructor, which calls # "disconnect" on the skeleton, ensuring that the propagation # we just did doesn't mess up the old skeleton context. skeletoncontext.skeletonContexts.add([msname, nm], newskel, parent=microstructure.microStructures[msname]) newskelcontext = skeletoncontext.skeletonContexts[[msname, nm]] newskelcontext.groupCopy(oldskelcontext)
def createMSFromImageFile(menuitem, filename, microstructure_name, height, width, depth=0): if (height!=automatic and height<=0) or \ (width!=automatic and width<=0) or \ (config.dimension()==3 and depth!=automatic and depth<=0): raise ooferror.ErrUserError( "Negative microstructure sizes are not allowed.") image = autoReadImage(filename, height, width, depth) ms = ooflib.common.microstructure.Microstructure(microstructure_name, image.sizeInPixels(), image.size()) immidgecontext = imagecontext.imageContexts.add( [ms.name(), image.name()], image, parent=ooflib.common.microstructure.microStructures[ms.name()]) if parallel_enable.enabled(): # For the rear-end guys from ooflib.image.IO import oofimageIPC oofimageIPC.imenu.Create_From_Imagefile_Parallel( msname=microstructure_name, imagename=image.name()) switchboard.notify("redraw")
def renamePixelGroup(menuitem, microstructure, group, new_name): if parallel_enable.enabled(): pixelgroupIPC.ipcpixgrpmenu.Rename(microstructure=microstructure, group=group, new_name=new_name) return # "group" arg is the old group name. mscontext = ooflib.common.microstructure.microStructures[microstructure] ms = mscontext.getObject() mscontext.begin_writing() renamed = False try: grp = ms.findGroup(group) # Don't just say "if grp" here. PixelGroup has a __len__ # function, so empty groups evaluate to "false". if grp is not None: ms.renameGroup(group, new_name) renamed = True if config.dimension() == 2 and runtimeflags.surface_mode: interfacemsplugin=ms.getPlugIn("Interfaces") interfacemsplugin.renameGroup(group, new_name) else: raise ooferror.ErrUserError("There is no pixel group named %s!" % group) finally: mscontext.end_writing() if renamed: switchboard.notify('renamed pixel group', grp, group, new_name)
def _skeleton_from_mstructure(menuitem, name, microstructure, x_elements, y_elements, skeleton_geometry): if parallel_enable.enabled(): # PARALLEL skeleton.initialSkeletonParallel(name, microstructure, x_elements, y_elements, skeleton_geometry) else: ms = microStructures[microstructure].getObject() skel = skeleton.initialSkeleton(name, ms, x_elements, y_elements, skeleton_geometry) switchboard.notify("redraw")
def _modify_callback(menuitem, skeleton, modifier): if parallel_enable.enabled(): from ooflib.engine.IO import skeletonIPC skeletonIPC.smenu.Modify(skeleton=skeleton, modifier=modifier) else: _modify(menuitem, skeleton, modifier)
def _ops_callback(menuitem, mesh, time, data, domain, sampling, destination, **kwargs): if parallel_enable.enabled(): menuitem.ipcmenu(mesh=mesh,data=data,domain=domain,sampling=sampling, destination=destination) return operation = menuitem.data() # data is a DataOperation Registration # Set the mesh in the domain, then run the operation. domain.set_mesh(mesh) domain.read_lock() # acquires Mesh's read lock. try: # The domain has all the mesh data, so we don't have to pass that data. meshctxt = ooflib.engine.mesh.meshes[mesh] meshctxt.precompute_all_subproblems() t = meshctxt.getTime(time) # converts '<latest>' to time, if needed meshctxt.restoreCachedData(t) destination.open() try: if sampling.make_samples(domain): printBulkHeaders(destination, operation, data, domain, sampling) # Do the calculation operation(t, data, domain, sampling, destination) finally: meshctxt.releaseCachedData() destination.close() finally: domain.read_release() # domain holds a reference to the mesh, and since it's a # Parameter value, the command history holds a reference to # domain. We need to clear the mesh reference so that the # mesh can be destroyed when everybody else is done with it. domain.set_mesh(None)
def _defineField(menuitem, subproblem, field): if parallel_enable.enabled(): ipcsubpmenu.Field.Define(subproblem=subproblem, field=field) else: # subproblem is a name, not an object subpcontext = ooflib.engine.subproblemcontext.subproblems[subproblem] subpcontext.reserve() subpcontext.begin_writing() didsomething = False try: if not subpcontext.is_defined_field(field): subpcontext.getObject().define_field(field) meshctxt = subpcontext.getParent() initializer = meshctxt.get_initializer(field) if initializer: initializer.apply(subpcontext.getParent().getObject(), field, singleFieldDef=True) meshctxt.update_fields() didsomething = True finally: subpcontext.end_writing() subpcontext.cancel_reservation() if didsomething: subpcontext.autoenableBCs() subpcontext.changed("Field defined.") switchboard.notify("field defined", subproblem, field.name(), 1) switchboard.notify("redraw")
def fmsg(*args): ## Importing ooferror here hangs the program when a binary data ## file is loaded if fmsg is used in OOFIdleCallback. WTF? There ## may be no real need to import ooferror here, but it was ## imported here once, and mysteriously caused a problem. ## (There's a comment in mainthreadGUI that refers to this ## comment.) # from ooflib.SWIG.common import ooferror if _debug_mode: lock.acquire() try: stack = traceback.extract_stack() depth = len(stack) filename = string.split(stack[-2][0], '/')[-1] func = stack[-2][2] line = stack[-2][1] try: thread = "%02d"% threadstate.findThreadNumber() except: thread = '??' if parallel_enable.enabled(): from ooflib.SWIG.common import mpitools rank="%02d" % mpitools.Rank() else: rank='--' print >> sys.stderr, \ ('-%04d-%s-%s'%(depth,thread,rank))+'-'*(depth-1), \ '%s(%d):%s'%(filename, line, func),\ string.join(map(str, args), ' ') finally: lock.release()
def __init__(self, nodes, index): SkeletonElementBase.__init__(self, nodes) skeletonselectable.SkeletonSelectable.__init__(self, index) # Although the CSkeletonElement keeps a list of # CSkeletonNodes, the extra information in the Python # SkeletonNodes isn't available unless we keep a list of them # here, as well. It's possible that we could move all the # extra info into the CSkeletonNode class and swig it. # Canonical ordering will still work, because it's based on # indices. self.nodes = nodes for node in nodes: node.addElement(self) # When a real mesh is made from the skeleton in which this # element lives, self.meshindex gets assigned the index of # that element. This index is the same for all the real meshes. self.meshindex = None self.ID = object_id.ObjectID() # process ID (only meaningful in parallel mode) if parallel_enable.enabled(): from ooflib.SWIG.common import mpitools self._procID = mpitools.Rank() else: self._procID = None
def __call__(self, time, output, domain, sampling, destination): if parallel_enable.enabled(): if mpitools.Rank()==0: _DirectOutput_call_frontend(output,domain,sampling, destination) else: _DirectOutput_call_backend(output,domain,sampling, destination) return # "olist" is a list of tuples of the form (sample, value). olist = sampling.evaluate(domain, output) header = sampling.get_col_names() if formatchars.showTime(): destination.comment("time:", `time`) for (s,v) in olist: tags = s.columnData(header) if len(tags)==1: for t in tags[0]: # tags[0] is a list of strings print >> destination, t, for x in v.value_list(): print >> destination, x, print >> destination else: # Multiple values -- do above for each tag-val pair. for (tag, val) in zip(tags, v): for t in tag: print >> destination, t, for x in val.value_list(): print >> destination, x, print >> destination
def copyMicrostructure(menuitem, microstructure, name): if parallel_enable.enabled(): microstructureIPC.msmenu.Copy(microstructure=microstructure,name=name) return ms = ooflib.common.microstructure.microStructures[microstructure] ms.begin_reading() grouplist = [] try: sourceMS = ms.getObject() newMS = sourceMS.nominalCopy(name) newMScontext = ooflib.common.microstructure.microStructures[name] # First, copy images and load them to copied MS. for imagectxt in sourceMS.getImageContexts(): sourceimage = imagectxt.getObject() immidge = sourceimage.clone(sourceimage.name()) imagecontext.imageContexts.add([newMS.name(),immidge.name()], immidge, parent=newMScontext) # Copy pixel groups for grpname in sourceMS.groupNames(): sourcegrp = sourceMS.findGroup(grpname) # Ignore "newness", all groups will be new. (newgrp, newness) = newMS.getGroup(grpname) newgrp.add(sourcegrp.members()) newgrp.set_meshable(sourcegrp.is_meshable()) grouplist.append(newgrp) finally: ms.end_reading() for g in grouplist: switchboard.notify("new pixel group", g)
def createMSFromImage(menuitem, name, width, height, image): if parallel_enable.enabled(): # For the back-end processes from ooflib.image.IO import oofimageIPC oofimageIPC.imenu.Create_From_Image_Parallel( msname=name, image=image) # For serial mode #0 in parallel mode imagepath = labeltree.makePath(image) immidgecontext = imagecontext.imageContexts[image] immidge = immidgecontext.getObject().clone(imagepath[-1]) size = immidge.size() # Point object. if width!=automatic.automatic: size[0]=width if height!=automatic.automatic: size[1]=height ms = ooflib.common.microstructure.Microstructure(name, immidge.sizeInPixels(), size) newimagecontext = imagecontext.imageContexts.add( [name, immidge.name()], immidge, parent=ooflib.common.microstructure.microStructures[name]) switchboard.notify("redraw")
def renameMicrostructure(menuitem, microstructure, name): if parallel_enable.enabled(): microstructureIPC.msmenu.Rename(microstructure=microstructure,name=name) return ms = ooflib.common.microstructure.microStructures[microstructure] ms.reserve() aa = ms.getObject().activearea aa.begin_writing() try: aa.rename(name) finally: aa.end_writing() ps = ms.getObject().pixelselection ps.begin_writing() try: ps.rename(name) finally: ps.end_writing() ms.begin_writing() try: ms.rename(name, exclude=ms.getObject().name()) finally: ms.end_writing() ms.cancel_reservation()
def copyPixelGroup(menuitem, microstructure, group, name): if parallel_enable.enabled(): pixelgroupIPC.ipcpixgrpmenu.Copy(microstructure=microstructure, group=group, name=name) return if group != name: mscontext = ooflib.common.microstructure.microStructures[microstructure] ms = mscontext.getObject() mscontext.begin_writing() newness = False try: oldgroup = ms.findGroup(group) if oldgroup is not None: (newgroup, newness) = ms.getGroup(name) newgroup.addWithoutCheck(oldgroup.members()) else: raise ooferror.ErrUserError("There is no pixel group named %s!" % group) finally: mscontext.end_writing() if newness: switchboard.notify("new pixel group", newgroup) switchboard.notify("changed pixel group", newgroup, microstructure)
def moveNode(self, menuitem, origin, destination): skelcontext = self.gfxwindow().topwho('Skeleton') if skelcontext: # if parallel_enable.enabled(): from ooflib.engine.IO import skeletonIPC skeletonIPC.smenu.Move_Node_Helper(origin=origin, destination=destination, allow_illegal=self.allow_illegal, skeletonpath=skelcontext.path()) return # skeleton = skelcontext.getObject().deputyCopy() skeleton.activate() node = skeleton.nearestNode(origin) skelcontext.reserve() skelcontext.begin_writing() try: skeleton.moveNodeTo(node, destination) if node.illegal(): if self.allow_illegal==1: skeleton.setIllegal() else: node.moveBack() elif skeleton.illegal(): # node motion may have rehabilitated skeleton.checkIllegality() skelcontext.pushModification(skeleton) finally: skelcontext.end_writing() skelcontext.cancel_reservation() skeleton.needsHash() switchboard.notify('redraw')
def queryElem(self, menuitem, position): context = self.gfxwindow().topwho(*self.whoset) if not context: return if parallel_enable.enabled(): meshIPC.ipcmeshmenu.Mesh_Info_Query(targetname="Element", position=position, mesh=context.path()) if mpitools.Rank()>0: return if position == self.last_position: meshpos = self.querier.mesh_position else: if config.dimension() == 2: try: context.restoreCachedData(self.gfxwindow().displayTime) try: meshpos = self.meshlayer.undisplaced_from_displaced( self.gfxwindow(), position) finally: context.releaseCachedData() except ooferror.ErrBoundsError: return elif config.dimension() == 3: # skip handling displaced meshes in 3D for now. # TODO 3D Later: figure this out meshpos = position femesh = context.getObject() skeleton = context.getSkeleton() selem = skeleton.enclosingElement(meshpos) felem = femesh.getElement(selem.meshindex) self.finishQuery(felem, felem, "Element", position, meshpos)
def _bcdisable(self, mesh, name): if parallel_enable.enabled(): boundaryconditionIPC.ipcbcmenu.Disable(mesh=mesh,name=name) return meshcontext = ooflib.engine.mesh.meshes[mesh] bndycond = meshcontext.getBdyCondition(name) bndycond.explicitly_disable() meshcontext.changed("Boundary conditions disabled")
def _wrapped_assignmat(menuitem, material, microstructure, pixels): _assignmat(material, microstructure, pixels) if parallel_enable.enabled(): try: from ooflib.SWIG.common import mpitools if mpitools.Rank() == 0: materialmenuIPC.ipcmaterialmenu.Assign(material = material, microstructure = microstructure, pixels = pixels) except ImportError: pass
def _copymaterial(menuitem, name, new_name): matmanager.copy(name, new_name) if parallel_enable.enabled(): try: from ooflib.SWIG.common import mpitools if mpitools.Rank() == 0: materialmenuIPC.ipcmaterialmenu.Copy(name = name, new_name = new_name) except ImportError: pass
def _bccopy(self, current, mesh, bc, name, boundary): if parallel_enable.enabled(): boundaryconditionIPC.ipcbcmenu.Copy(current=current,mesh=mesh,bc=bc,name=name,boundary=boundary) else: meshcontext = ooflib.engine.mesh.meshes[current] bndycond = meshcontext.getBdyCondition(bc) newbc = bndycond.copy(boundary) newbc.add_to_mesh(name, mesh) switchboard.notify("mesh changed", ooflib.engine.mesh.meshes[mesh])
def start_sockets_Back_End(): if parallel_enable.enabled(): from ooflib.common.IO import socket2me from ooflib.SWIG.common import mpitools ## receive from front end what port to listen s_address = mpitools.recv_bcast_string(0) s_name = mpitools.recv_bcast_string(0) ## create a unique SocketInput object socket2me.makeSocketInput(s_name, int(s_address), mpitools.Rank())
def dimIndependentInit(self, index): self._elements = [] self.ID = object_id.ObjectID() # parallel attributes if parallel_enable.enabled(): self._owners = [] # only for the initial Skeleton self._shared_with = [] # except me self._remote_index = {} # procID : remote index
def _skeleton_delete(menuitem, skeleton): if parallel_enable.enabled(): from ooflib.engine.IO import skeletonIPC skeletonIPC.smenu.Delete(skeleton=skeleton) else: skelctxt = skeletoncontext.skeletonContexts[skeleton] skelobj = skelctxt.getObject() skeletoncontext.skeletonContexts[skeleton].lockAndDelete()
def _deletewrapper(menuitem, property): if parallel_enable.enabled(): from ooflib.engine.IO import propertymenuIPC propertymenuIPC.ipcpropmenu.Delete(property=property) else: try: AllProperties.delete(property) except ooferror.ErrUserError, e: print e
def _copywrapper(menuitem, property, new_name): if parallel_enable.enabled(): from ooflib.engine.IO import propertymenuIPC propertymenuIPC.ipcpropmenu.Copy(property=property,new_name=new_name) else: try: AllProperties.new_prop(property, new_name) except ooferror.ErrUserError, e: print e
def parametrizercallback(self, menuitem, **kwargs): if parallel_enable.enabled(): OOF.LoadData.IPC.Property.Parametrize(**kwargs) else: # Translate the menuitem's path to the tree's path. The first # three words of the path are OOF.Property.Parametrize. # We want the remainder. treepath = string.split(menuitem.path(),".")[3:] reg = self.data[treepath].object reg.new_params(**kwargs) switchboard.notify("redraw")
def redoImageMod(menuitem, image): if parallel_enable.enabled(): from ooflib.image.IO import oofimageIPC oofimageIPC.imenu.Redo(image=image) who = imagecontext.imageContexts[image] who.begin_writing() oofimage.redoModification(image) who.end_writing() switchboard.notify('modified image', None, image) switchboard.notify('redraw')
def _newmaterial(menuitem, name, material_type=None): # Backward compatibility with old version without a material_type parameter material_type = material_type or MATERIALTYPE_BULK matmanager.add(name,material_type) if parallel_enable.enabled(): try: from ooflib.SWIG.common import mpitools if mpitools.Rank() == 0: materialmenuIPC.ipcmaterialmenu.New(name = name) except ImportError: pass
def _removeprop(menuitem, name, property): matmanager.remove_prop(name, property) if parallel_enable.enabled() == 1: try: from ooflib.SWIG.common import mpitools if mpitools.Rank() == 0: materialmenuIPC.ipcmaterialmenu.Remove_property( name=name, property=property) except ImportError: pass switchboard.notify("material changed", name) switchboard.notify("redraw")
def polygons(self, gfxwindow, meshctxt): # used only in 2D themesh = meshctxt.getObject() meshctxt.restoreCachedData(self.getTime(meshctxt)) try: # PARALLEL_RCL: Make changes here to display parallel mesh # There is an issue with clicking on the skeleton or mesh # graphics: only the nodes or elements for the front-end # process get the cursor or mark if parallel_enable.enabled(): # This snippet taken from SkeletonDisplayMethod nodes = themesh.all_meshskeletons["nodes"] elements = themesh.all_meshskeletons["elements"] polys = [] for i in range(mpitools.Size()): for el in elements[i]: polys.append( [primitives.Point(*nodes[i][ni]) for ni in el]) return polys else: edges = [element.perimeter() for element in themesh.elements()] flatedges = utils.flatten(edges) ## TODO MER: 2D version needs to change to get rid of ## PositionOutputs. 'where' is now a MeshNodePosition ## object. # corners tells where on each edge to evaluate self.where corners = [[0.0]] * len(flatedges) # evaluate position output for all edges at once polys = self.where.evaluate(themesh, flatedges, corners) # give the corner list the same structure as the edge list: a # list of lists, where each sublist is the list of corners of # an element. polys = utils.unflatten(edges, polys) if len(polys) == 0: mainthread.runBlock(reporter.warn, ( "No mesh elements drawn! Are there no materials assigned?", )) return polys finally: meshctxt.releaseCachedData()
def _rename_subproblem(menuitem, subproblem, name): if parallel_enable.enabled(): ipcsubpmenu.Rename(name=name, subproblem=subproblem) return oldpath = labeltree.makePath(subproblem) newpath = labeltree.makePath(subproblem)[:-1] + [name] subprob = ooflib.engine.subproblemcontext.subproblems[oldpath] old_dependents = subprob.subptype.get_dependents() if subprob.name() == ooflib.engine.mesh.defaultSubProblemName: raise ooferror.ErrUserError("You can't rename the default Subproblem!") for dependent in old_dependents: dependentsubp = ooflib.engine.subproblemcontext.subproblems[dependent] dependentsubp.subptype.sync_dependency(":".join(oldpath), ":".join(newpath)) subprob.reserve() subprob.begin_writing() try: subprob.rename(name, exclude=oldpath[-1]) finally: subprob.end_writing() subprob.cancel_reservation()
def newPixelGroup(menuitem, name, microstructure): if parallel_enable.enabled(): pixelgroupIPC.ipcpixgrpmenu.New(name=name, microstructure=microstructure) return if name and microstructure: mscontext = ooflib.common.microstructure.microStructures[ microstructure] ms = mscontext.getObject() mscontext.begin_writing() try: if ms: (grp, newness) = ms.getGroup(name) finally: mscontext.end_writing() if newness: switchboard.notify("new pixel group", grp) return grp reporter.report("Failed to create group", name, "in microstructure", microstructure)
def _ops_callback(menuitem, mesh, time, data, domain, sampling, destination, **kwargs): if parallel_enable.enabled(): menuitem.ipcmenu(mesh=mesh, data=data, domain=domain, sampling=sampling, destination=destination) return operation = menuitem.data() # data is a DataOperation Registration # Set the mesh in the domain, then run the operation. domain.set_mesh(mesh) domain.read_lock() # acquires Mesh's read lock. try: # The domain has all the mesh data, so we don't have to pass that data. meshctxt = ooflib.engine.mesh.meshes[mesh] meshctxt.precompute_all_subproblems() t = meshctxt.getTime(time) # converts '<latest>' to time, if needed meshctxt.restoreCachedData(t) destination.open() try: if sampling.make_samples(domain): printBulkHeaders(destination, operation, data, domain, sampling) # Do the calculation operation(t, data, domain, sampling, destination) finally: meshctxt.releaseCachedData() destination.close() finally: domain.read_release() # domain holds a reference to the mesh, and since it's a # Parameter value, the command history holds a reference to # domain. We need to clear the mesh reference so that the # mesh can be destroyed when everybody else is done with it. domain.set_mesh(None)
def cleanup(shutdownfn, exitstatus): # Turn off logging, so that window closing, etc. won't be logged. mainmenu.OOF.haltLog() gfxmanager.gfxManager.closeAllWindows() for fn in _cleanUpActions: fn() if parallel_enable.enabled(): try: from ooflib.SWIG.common import mpitools if mpitools.Rank() == 0: # tell back-end to start quit process mainmenu.OOF.LoadData.IPC.Quit() except ImportError: pass # Wait on a subthread for threads to finish, then call shutdownfn # on the main thread. When called from the GUI callback for the # Quit command, shutdownfn is common.IO.GUI.quit.shutdown. subthread.execute_immortal(waitForThreads, (shutdownfn, exitstatus))
def queryNode(self, menuitem, position): context = self.gfxwindow().topwho(*self.whoset) if not context: return if parallel_enable.enabled(): meshIPC.ipcmeshmenu.Mesh_Info_Query( targetname="Node", position=position,mesh=context.path()) if mpitools.Rank()>0: return if position == self.last_position: meshpos = self.querier.mesh_position else: if config.dimension() == 2: try: context.restoreCachedData(self.gfxwindow().displayTime) try: meshpos = self.meshlayer.undisplaced_from_displaced( self.gfxwindow(), position) finally: context.releaseCachedData() except ooferror.ErrBoundsError: return elif config.dimension() == 3: # skip handling displaced meshes in 3D for now. # TODO 3D Later: figure this out meshpos = position femesh = context.getObject() skeleton = context.getSkeleton() selem = skeleton.enclosingElement(meshpos) felem = femesh.getElement(selem.meshindex) if config.dimension() == 2: fnode = femesh.closestNode(meshpos.x, meshpos.y) elif config.dimension() == 3: fnode = femesh.closestNode(meshpos.x, meshpos.y, meshpos.z) self.finishQuery(fnode, felem, "Node", position, meshpos)
def _copyEquationState(menuitem, source, target): if source == target: raise ooferror.ErrUserError('Source and target must differ!') if parallel_enable.enabled(): ipcsubpmenu.Copy_Equation_State(source=source, target=target) return notifications = [] source_subp = ooflib.engine.subproblemcontext.subproblems[source] target_subp = ooflib.engine.subproblemcontext.subproblems[target] source_subp.begin_reading() target_subp.reserve() target_subp.begin_writing() try: source_obj = source_subp.getObject() target_obj = target_subp.getObject() source_eqns = source_obj.all_equations() target_eqns = target_obj.all_equations() for e in target_eqns: if not source_obj.is_active_equation(e): target_obj.deactivate_equation(e) notifications.append( ("equation activated", target, e.name(), 0)) for e in source_eqns: if not target_obj.is_active_equation(e): target_obj.activate_equation(e) notifications.append( ("equation activated", target, e.name(), 1)) finally: source_subp.end_reading() target_subp.end_writing() target_subp.cancel_reservation() for n in notifications: switchboard.notify(*n) target_subp.autoenableBCs() target_subp.changed("Equations changed.")
def newMicrostructure(menuitem, name, width, height, depth, width_in_pixels, height_in_pixels, depth_in_pixels): if width<=0 or height<=0 or depth<=0 \ or width_in_pixels<=0 or height_in_pixels<=0 or depth_in_pixels<=0: raise ooferror.ErrUserError("Negative size values are not allowed.") if parallel_enable.enabled(): # For the rear-end guys microstructureIPC.msmenu.New_Parallel(name=name, width=width, height=height, depth=depth, width_in_pixels=width_in_pixels, height_in_pixels=height_in_pixels, depth_in_pixels=depth_in_pixels) # Serial mode & #0 in parallel mode ms = ooflib.SWIG.common.cmicrostructure.CMicrostructure( name, primitives.iPoint(width_in_pixels, height_in_pixels, depth_in_pixels), primitives.Point(width, height, depth) )
def doImageMod(menuitem, image, **params): if parallel_enable.enabled(): from ooflib.image.IO import oofimageIPC paramenu = oofimageIPC.modmenu.getItem(menuitem.name) paramenu(image=image, **params) # image is the image name, actually imagectxt = imagecontext.imageContexts[image] imagectxt.reserve() try: immidge = imagectxt.getObject() # OOFImage object newimmidge = immidge.clone(immidge.name()) registration = menuitem.data imageModifier = registration(**params) # create ImageModifier obj imagectxt.begin_writing() try: imageModifier(newimmidge) # call its __call__ method on the image oofimage.pushModification(image, newimmidge) finally: imagectxt.end_writing() finally: imagectxt.cancel_reservation() switchboard.notify('modified image', imageModifier, image) switchboard.notify('redraw')
def meshablePixelGroup(menuitem, microstructure, group, meshable): if parallel_enable.enabled(): pixelgroupIPC.ipcpixgrpmenu.Meshable(microstructure=microstructure, group=group, meshable=meshable) return mscontext = ooflib.common.microstructure.microStructures[microstructure] ms = mscontext.getObject() mscontext.begin_writing() try: grp = ms.findGroup(group) if grp is not None: grp.set_meshable(meshable) ms.recategorize() else: raise ooferror.ErrUserError("There is no pixel group named %s!" % group) finally: mscontext.end_writing() switchboard.notify('redraw') if grp is not None: switchboard.notify("changed pixel group", grp, microstructure)
def dumpTrace(start=0, end=-1): ## Use start=-3, end=-2 if you only want to see the calling ## function of the function that calls dumpTrace. lock.acquire() try: stack = traceback.extract_stack() depth = len(stack) thread = threadstate.findThreadNumber() if parallel_enable.enabled(): from ooflib.SWIG.common import mpitools rank="%02d" % mpitools.Rank() else: rank='--' lines = ['+++-%04d-%02d-%s--------- debug.dumpTrace --------------' % (depth, thread, rank) ] for line in stack[start:end]: lines.append('+++%30s:%3d\t%s\t\t%s' % (line[0],line[1], line[2],line[3])) lines.append('+++-------------- end trace -----------------') print >> sys.stderr, string.join(lines, '\n') finally: lock.release()
def _undefineField(menuitem, subproblem, field): if parallel_enable.enabled(): ipcsubpmenu.Field.Undefine(subproblem=subproblem, field=field) else: subpcontext = ooflib.engine.subproblemcontext.subproblems[subproblem] subpcontext.reserve() subpcontext.begin_writing() try: subpcontext.getObject().undefine_field(field) subpcontext.getParent().update_fields() # After undefining a Field, the data cache in the mesh has # the wrong number of dofs in it. We could in principle # delete the correct dofs from each cache entry, but it # might be slow (especially for a disk cache). The # simpler thing to do is to just delete the whole cache. subpcontext.getParent().clearDataCache() finally: subpcontext.end_writing() subpcontext.cancel_reservation() subpcontext.autoenableBCs() subpcontext.changed("Field undefined.") switchboard.notify("field defined", subproblem, field.name(), 0) switchboard.notify("redraw")
def _activateField(menuitem, subproblem, field): activation = False if parallel_enable.enabled(): ipcsubpmenu.Field.Activate(subproblem=subproblem, field=field) else: subpcontext = ooflib.engine.subproblemcontext.subproblems[subproblem] subpcontext.reserve() subpcontext.begin_writing() try: subp = subpcontext.getObject() if subp.is_defined_field(field): subp.activate_field(field) activation = True else: reporter.report( "You must define a Field before you can activate it.") finally: subpcontext.end_writing() subpcontext.cancel_reservation() if activation: subpcontext.autoenableBCs() switchboard.notify("field activated", subproblem, field.name(), 1) subpcontext.changed("Field activated.")
def createMSFromImage(menuitem, name, width, height, image): if parallel_enable.enabled(): # For the back-end processes from ooflib.image.IO import oofimageIPC oofimageIPC.imenu.Create_From_Image_Parallel(msname=name, image=image) # For serial mode #0 in parallel mode imagepath = labeltree.makePath(image) immidgecontext = imagecontext.imageContexts[image] immidge = immidgecontext.getObject().clone(imagepath[-1]) size = immidge.size() # Point object. if width != automatic.automatic: size[0] = width if height != automatic.automatic: size[1] = height ms = ooflib.SWIG.common.cmicrostructure.CMicrostructure( name, immidge.sizeInPixels(), size) newimagecontext = imagecontext.imageContexts.add( [name, immidge.name()], immidge, parent=ooflib.common.microstructure.microStructures[name]) switchboard.notify("redraw")
def _bcrename(menuitem, mesh, bc, name): if parallel_enable.enabled(): boundaryconditionIPC.ipcbcmenu.Rename(mesh=mesh, bc=bc, name=name) else: meshcontext = ooflib.engine.mesh.meshes[mesh] meshcontext.renameBdyCondition(bc, name)
def _modify_callback(menuitem, skeleton, modifier): if parallel_enable.enabled(): from ooflib.engine.IO import skeletonIPC skeletonIPC.smenu.Modify(skeleton=skeleton, modifier=modifier) else: _modify(menuitem, skeleton, modifier)
class Refine(skeletonmodifier.SkeletonModifier): def __init__(self, targets, criterion, degree, alpha): self.targets = targets # RefinementTarget instance self.criterion = criterion # Criterion for refinement self.degree = degree # RefinementDegree instance # alpha is used for deciding between different possible # refinements, using effective energy self.alpha = alpha # Available rules for the specified rule_set of refinement degree self.rules = refinemethod.getRuleSet(self.degree.rule_set.name) ######### def apply(self, skeleton, context): prog = progress.getProgress("Refine", progress.DEFINITE) try: newSkeleton = skeleton.improperCopy(skeletonpath=context.path()) return self.refinement(skeleton, newSkeleton, context, prog) finally: prog.finish() def applyAMR(self, skeleton): # for adaptive mesh refinement prog = progress.getProgress("Refine", progress.DEFINITE) try: newSkeleton = skeleton.improperCopy(fresh=True) return self.refinement(skeleton, newSkeleton, None, prog) finally: prog.finish() def refinement(self, skeleton, newSkeleton, context, prog): # Copy the old skeleton, without copying the elements. ## newSkeleton = skeleton.improperCopy() markedEdges = EdgeMarkings() self.newEdgeNodes = {} # allows sharing of new edge nodes # Primary marking self.targets(skeleton, context, self.degree.divisions, markedEdges, self.criterion) # Additional marking if config.dimension() == 2: self.degree.markExtras(skeleton, markedEdges) # Refine elements and segments segmentdict = {} # which segments have been handled n = len(skeleton.elements) if config.dimension() == 2: elements = skeleton.elements # for 3d, we reorder the elements so that those with # edgemarkings that can lead to deadlocks are treated first. if config.dimension() == 3: elements = [] nondeadlockable = [] for ii in range(n): oldElement = skeleton.elements[ii] marks = markedEdges.getMarks(oldElement) signature = findSignature(marks) if signature in refinemethod.deadlockableSignatures: elements.append(oldElement) else: nondeadlockable.append(oldElement) random.shuffle(elements) elements.extend(nondeadlockable) for ii in range(n): oldElement = elements[ii] oldnnodes = oldElement.nnodes() # For 2D: Find the canonical order for the marks. (The # order is ambiguous due to the arbitrary choice of the # starting edge. Finding the canonical order allows the # refinement rule to be found in the rule table.) # rotation (the first member of signature_info) is the # offset into the elements node list required to match the # refinement rule to the element's marked edges. # signature is the canonical ordering of the marks. For # 3D: The signature info is simply a tuple listing the # marked edges in order. We can no longer use a canonical # order and rotation since the ordering of the edges is no # longer arbitrary. # Get list of number of subdivisions on each edge ("marks") marks = markedEdges.getMarks(oldElement) signature_info = findSignature(marks) # Create new nodes along the subdivided element edges edgenodes = [ self.getNewEdgeNodes(nodes[0], nodes[1], marks[i], newSkeleton, skeleton) for nodes, i in zip(oldElement.segment_node_iterator(), range(oldElement.getNumberOfEdges())) ] # Create new elements if config.dimension() == 2: signature = signature_info[1] elif config.dimension() == 3: signature = signature_info newElements = self.rules[signature].apply(oldElement, signature_info, edgenodes, newSkeleton, self.alpha) # If the old element's homogeneity is "1", it's safe to say that # new elements' homogeneities are "1". if oldElement.homogeneity(skeleton.MS) == 1.0: for el in newElements: el.copyHomogeneity(oldElement) # The calls to Skeleton.newElement() made by the # refinement rules have created new SkeletonSegments in # newSkeleton, but have not set the parentage of those # segments. We have to fix that here. for newElement in newElements: for segment in newElement.getSegments(newSkeleton): # Only look at each segment once. if segment not in segmentdict: segmentdict[segment] = 1 pseg = findParentSegment(skeleton, newElement, segment, edgenodes) if pseg: pseg.add_child(segment) segment.add_parent(pseg) if prog.stopped(): return None else: prog.setFraction(1.0 * (ii + 1) / n) prog.setMessage("%d/%d" % (ii + 1, n)) newSkeleton.cleanUp() # Make sure not to keep a reference to anything in the # Skeleton, or the Skeleton won't be deleted properly. This # Refine object might nto be deleted, since it's kept in a # history buffer. del self.newEdgeNodes return newSkeleton ################ def getNewEdgeNodes(self, node0, node1, ndivs, newSkeleton, oldSkeleton): # Create ndivs new nodes between node0 and node1 in the # skeleton. node0 and node1 are from the old skeleton if ndivs < 1: return [] key = skeletonnode.canonical_order(node0, node1) try: #Unlike in snaprefine.py, we don't make a list copy. nodes = self.newEdgeNodes[key] if config.dimension() == 2: # Since this is the second time we're using this list # of nodes, we must be looking at them from the other # side, and the nodes should be in the opposite order. # Reversing them in place like this would be wrong if # the list weren't being used immediately, as it is in # Refine.apply() # don't do this in 3D because for now # we are only doing bisection, and because order # doesn't have the same meaning in 3d. nodes.reverse() except KeyError: nodes = [None] * ndivs p0 = node0.position() p1 = node1.position() delta = (p1 - p0) / (ndivs + 1) for i in range(ndivs): pt = p0 + (i + 1) * delta nodes[i] = newSkeleton.newNodeFromPoint(pt) self.newEdgeNodes[key] = nodes ## Begin Periodic Skeleton Node Construction ################### partners = node0.getPartnerPair(node1) # It can happen that partners contains the same two nodes # (node1,node0), if the Skeleton is only one element wide! if partners and node0 != partners[1]: partnerKey = skeletonnode.canonical_order( partners[0], partners[1]) # Make new edge nodes for the partner-edge. ndivs for # the current edge and the partner-edge must be the # same. nodespartner = [None] * ndivs s = newSkeleton.MS.size() n0pt = node0.position() n1pt = node1.position() # in 2D only one of the first four cases can be met, # but in 3D a combination of two of the following six # cases can be met and we must test that the # appropriate periodicity is in the skeleton partnerdict = {} # Case 1: boundary at left edge or face if n0pt.x == 0 and n1pt.x == 0 and newSkeleton.left_right_periodicity: partnerdict[0] = s[0] # Case 2: boundary at right edge or face elif n0pt.x == s[0] and n1pt.x == s[ 0] and newSkeleton.left_right_periodicity: partnerdict[0] = 0 # Case 3: boundary at bottom edge or face if n0pt.y == 0 and n1pt.y == 0 and newSkeleton.top_bottom_periodicity: partnerdict[1] = s[1] # Case 4: boundary at top edge or face elif n0pt.y == s[1] and n1pt.y == s[ 1] and newSkeleton.top_bottom_periodicity: partnerdict[1] = 0 if config.dimension() == 3: # Case 5: boundary at back edge or face if n0pt.z == 0 and n1pt.z == 0 and newSkeleton.front_back_periodicity: partnerdict[2] = s[2] # Case 6: boundary at front edge or face elif n0pt.z == s[2] and n1pt.z == s[ 2] and newSkeleton.top_bottom_periodicity: partnerdict[2] = 0 for i in range(ndivs): pt = nodes[i].position() for c, v in partnerdict.iteritems(): pt[c] = v newnodepartner = newSkeleton.newNodeFromPoint(pt) nodes[i].addPartner(newnodepartner) nodespartner[i] = newnodepartner self.newEdgeNodes[partnerKey] = nodespartner ## End Periodic Skeleton Node Construction ################### return nodes # parallel fuctions if parallel_enable.enabled(): def apply_parallel(self, skeleton, context): newSkeleton = skeleton.improperCopy( skeletonpath=context.path()) # fresh=False return self.refinement_parallel(skeleton, newSkeleton, context) def refinement_parallel(self, skeleton, newSkeleton, context): pass # Look in "refineParallel.py" def shareCommonNodes(self, markedEdges, skeleton, newSkeleton): pass # Look in "refineParallel.py"
def set_performance_cost(): if parallel_enable.enabled(): ## initialization global performance ## everyone: back-end + front-end performance.estimate_computational()
def _renamematerial(menuitem, material, name): if parallel_enable.enabled(): materialmenuIPC.ipcmaterialmenu.Rename(material=material, name=name) else: matmanager.rename(material, name)
def __call__(self, skeleton, node): if parallel_enable.enabled(): if node.isShared(): # Implicitly, it's mine too. return self.active(skeleton, node) return self.default(skeleton, node)
def deleteMicrostructure(menuitem, microstructure): if parallel_enable.enabled(): microstructureIPC.msmenu.Delete(microstructure=microstructure) else: mscontext = ooflib.common.microstructure.microStructures[microstructure] mscontext.lockAndDelete()
class FiddleNodes: def __init__(self, targets, criterion, T, iteration): self.targets = targets self.criterion = criterion self.T = T self.iteration = iteration self.nok = 0 self.nbad = 0 self.deltaE = 0 self.totalE = 0 ## self.movedPosition is set in derived classes. def makeProgress(self): return progress.getProgress(self.__class__.__name__, self.iteration.get_progressbar_type()) def apply(self, oldskeleton, context): prog = self.makeProgress() prog.setMessage(self.intro) return oldskeleton.deputyCopy() def updateIteration(self, prog): if self.nok + self.nbad > 0: self.iteration.update(self.deltaE, self.totalE, (1.0 * self.nok) / (self.nok + self.nbad), self.count, prog) else: self.iteration.update(None, None, None, self.count, prog) def postProcess(self, context): ## global Pcount ## Pcount += 1 ## random.seed(1) skeleton = context.getObject() prog = self.makeProgress() self.count = 0 prog.setMessage(self.header) before = skeleton.energyTotal(self.criterion.alpha) while self.iteration.goodToGo(): self.count += 1 # the context acquires the writing permissions inside # coreProcess. self.coreProcess(context) self.updateIteration(prog) skeleton.updateGeometry() switchboard.notify("skeleton homogeneity changed", context.path()) if prog.stopped(): break switchboard.notify("skeleton nodes moved", context) if prog.stopped(): self.targets.cleanUp() return after = skeleton.energyTotal(self.criterion.alpha) if before: rate = 100.0 * (before - after) / before else: rate = 0.0 diffE = after - before reporter.report("%s deltaE = %10.4e (%6.3f%%)" % (self.outro, diffE, rate)) self.targets.cleanUp() prog.finish() def coreProcess(self, context): ## NOTE FOR DEVELOPERS: #### if a change is made to this function, #### make sure that the SAME changes are made, in a #### consistent way in fiddlenodesbaseParallel.py skeleton = context.getObject() prog = self.makeProgress() self.totalE = skeleton.energyTotal(self.criterion.alpha) self.nok = self.nbad = 0 self.deltaE = 0. # TODO: If the Skeleton is periodic and a node and its partner # are both active, only one of them should be in activenodes. activenodes = self.targets(context) random.shuffle(activenodes) j = 0 context.begin_writing() try: # start_time = time.time() for node in activenodes: change = deputy.DeputyProvisionalChanges() change.moveNode(node, self.movedPosition(skeleton, node), skeleton) bestchange = self.criterion([change], skeleton) if bestchange is not None: self.nok += 1 self.deltaE += bestchange.deltaE(skeleton, self.criterion.alpha) bestchange.accept(skeleton) # Failed to meet the specified criterion ... but elif (self.T > 0.0 and not change.illegal(skeleton) and not self.criterion.hopeless()): diffE = change.deltaE(skeleton, self.criterion.alpha) if math.exp(-diffE / self.T) > random.random(): self.nok += 1 self.deltaE += diffE change.accept(skeleton) else: self.nbad += 1 else: self.nbad += 1 if prog.stopped(): return skeleton.timestamp.increment() finally: prog.finish() context.end_writing() switchboard.notify("redraw") # Parallel function if parallel_enable.enabled(): def apply_parallel(self, oldskeleton, context): pass # Look in "fiddlenodesbaseParallel.py" def updateIteration_parallel(self): pass # "fiddlenodesbaseParallel.py" def postProcess_parallel(self, context): pass # Defined in "fiddlenodesbaseParallel.py" def coreProcess_parallel(self, context): pass # defined in "fiddlenodesParallel.py"
def get_bounds(self): if parallel_enable.enabled(): return self.skeleton.localbounds else: return primitives.Rectangle(primitives.Point(0.0,0.0), self.ms.size())
class SkeletonElement(SkeletonElementBase, skeletonselectable.SkeletonSelectable): def __init__(self, nodes, index): SkeletonElementBase.__init__(self, nodes) skeletonselectable.SkeletonSelectable.__init__(self, index) # Although the CSkeletonElement keeps a list of # CSkeletonNodes, the extra information in the Python # SkeletonNodes isn't available unless we keep a list of them # here, as well. It's possible that we could move all the # extra info into the CSkeletonNode class and swig it. # Canonical ordering will still work, because it's based on # indices. self.nodes = nodes for node in nodes: node.addElement(self) # When a real mesh is made from the skeleton in which this # element lives, self.meshindex gets assigned the index of # that element. This index is the same for all the real meshes. self.meshindex = None self.ID = object_id.ObjectID() # process ID (only meaningful in parallel mode) if parallel_enable.enabled(): from ooflib.SWIG.common import mpitools self._procID = mpitools.Rank() else: self._procID = None # There may be some temptation to provide elements with an # index-based equality comparison function. Doing this is # dangerous, as it screws up the parent/child addition machinery # in the parent SkeletonSelection class. def repr_position(self): return self.center() def getIndex(self): return self.index #Interface branch def getNodeIndexIntoList(self,node): ## TODO OPT: This seems to be called a lot. Why not create a ## lookup table, or store the index in the node? return self.nodes.index(node) def type(self): return self.shapetype def destroy(self, skeleton): self.disconnect() nnodes = self.nnodes() lastnode = self.nodes[-1] for node in self.nodes: skeleton.findSegment(lastnode, node).removeElement(skeleton, self) node.removeElement(skeleton, self) lastnode = node self.nodes = [] # def getFEelement(self): # return self.element def getSegments(self, skeleton): segments = [] lastnode = self.nodes[-1] for node in self.nodes: segments.append(skeleton.findSegment(node, lastnode)) lastnode = node return segments #Interface branch #Get the segment opposite seg1 and that is incident on node1. #seg1 and the segment we are looking for form a 'V'. def getOppositeSegment(self, node1, seg1, skeleton): for node in self.nodes: if node!=node1: oseg=skeleton.findSegment(node,node1) if oseg is not None and oseg!=seg1: return oseg def nodesInOrder(self, node0, node1): lastnode = self.nodes[-1] for node in self.nodes: if node0==lastnode and \ node1==node: return 1 lastnode=node return 0 def getSegmentOrderNumber(self, seg, skeleton): lastnode = self.nodes[-1] i=0 for node in self.nodes: if seg==skeleton.findSegment(node, lastnode): return i lastnode=node i+=1 return -1 def getSegmentFromOrderNumber(self, ordernumber, skeleton): lastnode = self.nodes[-1] i=0 for node in self.nodes: if i==ordernumber: return skeleton.findSegment(node, lastnode) lastnode=node i+=1 return None def active(self, skeleton): for node in self.nodes: if node.active(skeleton): return 1 return 0 def new_child(self,index): raise ooferror2.ErrPyProgrammingError( "Attempt to clone element parent class.") def getNumberOfEdges(self): return self.nnodes() def segment_node_iterator(self): segment_nodes = [] for i in range(self.nnodes()): n0 = self.nodes[i] n1 = self.nodes[(i+1)%self.nnodes()] segment_nodes.append((n0,n1)) return segment_nodes def segment_iterator(self, skel): segments = [] for i in range(self.nnodes()): n0 = self.nodes[i] n1 = self.nodes[(i+1)%self.nnodes()] segments.append(skel.findSegment(n0, n1)) return segments def edgeNeighbors(self, skeleton, loopRange=0): # Search for edge-sharing neighborhood for a given element and return # a list of them. nnodes = self.nnodes() edgeNeighborList = [None]*nnodes for i in range(nnodes): segment = skeleton.findSegment(self.nodes[i], self.nodes[(i+1)%nnodes]) if segment is not None: edgeNeighborList[i] = segment.getOtherElement(self) # this should only work if the segment is on a periodic boundary # in which case the above call to getOtherElement should have # returned nothing partners = self.nodes[i].getPartnerPair(self.nodes[(i+1)%nnodes]) if partners is not None: segment = skeleton.findSegment(partners[0],partners[1]) if segment is not None: edgeNeighborList[i] = segment.getOtherElement(self) return edgeNeighborList def getEdgeLengthsList(self): list = [] for i in range(self.nnodes()): list.append(self.edgeLength(i)) return list def getShortestEdge(self): list = self.getEdgeLengthsList() minEdge = list[0] index = 0 for i in range(1, self.nnodes()): if list[i] < minEdge: minEdge = list[i] index = i return index def getAnglesList(self): # list = [] # for i in range(self.nnodes()): # list.append(self.cosCornerAngle(i)) # return list return [self.cosCornerAngle(i) for i in range(self.nnodes())] def getBiggestAngle(self): list = self.getAnglesList() maxAngle = list[0] # cosine of the angle index = 0 for i in range(1, self.nnodes()): if list[i] < maxAngle: maxAngle = list[i] index = i return index def getSister(self, skeleton, node0, node1): # 4 _________ 3 # \ / # \ A / If an edge 1-2 of the element A needs to be modified # \ / (for example, collapsing), it is important to update # 1 \_/ 2 its edge-sharing neighbor element B. # / \ This function returns a sister element of "self" which # / \ shares an edge (node1-node2). # / B \ # --------- segment = skeleton.findSegment(node0, node1) elements = segment.getElements() ## if len(elements) > 2: ## raise ooferror2.ErrPyProgrammingError("Too many sisters!") for e in elements: if e is not self: return e return None # edge boundary def getSisterPeriodic(self, skeleton, node0, node1): segment = skeleton.findSegment(node0, node1) elements = segment.getElements() for e in elements: if e is not self: return e partnerseg = segment.getPartner(skeleton) if partnerseg: return partnerseg.getElements()[0] return None def replacementNodes(self, oldnode, newnode): nodelist = self.nodes[:] which = nodelist.index(oldnode) nodelist[which] = newnode return nodelist # Parallel stuff if parallel_enable.enabled(): def belongTo(self, bbox): # called from "engine.IO.skeletonIPC" c = self.center() xmin = bbox.lowerLeft[0] ymin = bbox.lowerLeft[1] xmax = bbox.upperRight[0] ymax = bbox.upperRight[1] return (xmin<=c[0] and c[0]<xmax) and (ymin<=c[1] and c[1]<ymax) def resetProcID(self, id): self._procID = id # id is the id of the process # ... and for the nodes for nd in self.nodes: nd.addOwner(id) def procID(self): return self._procID ######################### #Interface branch def realelement(self, skeletoncontext, mesh, index, fe_node, seg_dict, elemdict, materialfunc): # Create a real element corresponding to this skeleton # element. The elemdict argument is a dictionary (keyed by the # number of sides of the element) of MasterElement objects, # which contain the information needed to construct the real # elements. "index" is the SkeletonElement's position in the # Skeleton's list, and "fe_node" is a dictionary of real nodes # in the FEMesh, indexed by their corresponding SkeletonNode # objects. The lists give the nodes in the order in which # they were added to the element. # Be safe with indices. if self.meshindex is None: # Zero is nontrivial index. self.meshindex = index else: if index != self.meshindex: raise ooferror2.ErrPyProgrammingError( "Index mismatch in element construction.") nnewnodes = 0 ncn = len(self.nodes) # Corner nodes. # elemdict is a dictionary of MasterElements, keyed by number # of sides. elementtype = elemdict[self.nnodes()] nodes = [] # real nodes for this element for i in range(len(self.nodes)): # i.e. for each edge... c0 = self.nodes[i] nodes.append(fe_node[c0]) # Corner nodes already exist. c1 = self.nodes[(i+1)%ncn] cset = skeletonnode.canonical_order(c0, c1) # Look up this edge in the dictionary. If it's there, # then nodes have been created on the edge already, and we # should reuse them. try: xtranodes = mesh.getEdgeNodes(cset) # The nodes were created by the neighboring element. # Since elements traverse their edges counterclockwise # when creating nodes, the preexisting nodes are in # the wrong order for the current element. xtranodes.reverse() except KeyError: # The edge wasn't in the dictionary. It's a new edge. xtranodes = [] # Loop over all protonodes on the current # edge of the new element for newproto in elementtype.protodic[i]: masterxy = primitives.Point(newproto.mastercoord()[0], newproto.mastercoord()[1]) realxy = self.frommaster(masterxy, 0) newnode = _makenewnode(mesh, newproto, coord.Coord(realxy.x, realxy.y)) nnewnodes = nnewnodes + 1 xtranodes.append(newnode) #Interface branch try: #If the segment represented by cset is a member of an #interface, then new edge nodes (xtranodes) will #not be shared by another element. test=seg_dict[cset] except KeyError: mesh.addEdgeNodes(cset, xtranodes) nodes = nodes + xtranodes # Interior nodes at the end. for newproto in elementtype.protodic['interior']: masterxy = primitives.Point(newproto.mastercoord()[0], newproto.mastercoord()[1]) realxy = self.frommaster(masterxy, 0) newnode = _makenewnode(mesh, newproto, coord.Coord(realxy.x, realxy.y)) nnewnodes = nnewnodes + 1 nodes.append(newnode) mesh.addInternalNodes(self, newnode) # Having constructed the list of nodes, call the real # element's constructor. materialfunc returns the element's # material. In normal operation, materialfunc is # SkeletonElement.realmaterial. realel = elementtype.build(self, materialfunc(self, skeletoncontext), nodes) mesh.addElement(realel) # Add to mesh. # Tell the element about its exterior edges. for edge in self.exterior_edges: realel.set_exterior(fe_node[edge[0]], fe_node[edge[1]]) return nnewnodes ######################### # For parallel mesh construction. Non-corner nodes are given # sharing information based on the corner nodes that bound the # segment where the non-corner nodes are found. Called in # Skeleton.femesh_shares. These edge nodes are shared by at most # two processors (2D). Assume the number of protonodes in an edge # can't be anywhere close to 50. def realelement_shares(self, skeleton, mesh, index, fe_node, curnodeindex, elemdict, materialfunc): # Be safe with indices. if self.meshindex is None: # Zero is nontrivial index. self.meshindex = index else: if index != self.meshindex: raise ooferror2.ErrPyProgrammingError( "Index mismatch in element construction.") nnewnodes = 0 ncn = len(self.nodes) # Corner nodes. # elemdict is a dictionary of MasterElements, keyed by number # of sides. elementtype = elemdict[self.nnodes()] nodes = [] # real nodes for this element for i in range(len(self.nodes)): # i.e. for each edge... c0 = self.nodes[i] nodes.append(fe_node[c0]) # Corner nodes already exist. c1 = self.nodes[(i+1)%ncn] cset = skeletonnode.canonical_order(c0, c1) # Look up this edge in the dictionary. If it's there, # then nodes have been created on the edge already, and we # should reuse them. try: xtranodes = mesh.getEdgeNodes(cset) # The nodes were created by the neighboring element. # Since elements traverse their edges counterclockwise # when creating nodes, the preexisting nodes are in # the wrong order for the current element. xtranodes.reverse() except KeyError: newindexinc=0 newindex=0 protocount=0 protodiclength=len(elementtype.protodic[i]) if c0.index<c1.index: newindexinc=1 newindex=skeleton.maxnnodes+100*c0.index else: # Do this to distinguish the protonode on either # side of a corner node that has a smaller index # than either corner nodes of the collinear # segments extending from that corner node. newindexinc=-1 newindex=skeleton.maxnnodes+100*c1.index+50+protodiclength-1 # The edge wasn't in the dictionary. It's a new edge. xtranodes = [] # Loop over all protonodes on the current # edge of the new element for newproto in elementtype.protodic[i]: masterxy = primitives.Point(newproto.mastercoord()[0], newproto.mastercoord()[1]) realxy = self.frommaster(masterxy, 0) newnode = _makenewnode_shares( mesh, newproto, coord.Coord(realxy.x, realxy.y), c0,c1,newindex,protocount, protodiclength,skeleton.maxnnodes) newindex+=newindexinc protocount+=1 nnewnodes = nnewnodes + 1 xtranodes.append(newnode) mesh.addEdgeNodes(cset, xtranodes) #Should this be 'join'ed instead, for speed? nodes = nodes + xtranodes # Interior nodes at the end. for newproto in elementtype.protodic['interior']: masterxy = primitives.Point(newproto.mastercoord()[0], newproto.mastercoord()[1]) realxy = self.frommaster(masterxy, 0) newnode = _makenewnode(mesh, newproto, coord.Coord(realxy.x, realxy.y)) nnewnodes = nnewnodes + 1 nodes.append(newnode) mesh.addInternalNodes(self, newnode) # Having constructed the list of nodes, call the real # element's constructor. realel = elementtype.build(self, materialfunc(self, skeleton), nodes) # Long-lost cousin of Kal-El and Jor-El. mesh.addElement(realel) # Add to mesh. # Tell the element about its exterior edges. for edge in self.exterior_edges: realel.set_exterior(fe_node[edge[0]], fe_node[edge[1]]) return nnewnodes def realmaterial(self, skeletoncontext): return self.material(skeletoncontext)
def run(no_interp=None): global _rank global startupfiles process_inline_options() # execute well-formed oof options # Look for .oof2rc in the user's home directory. if not no_rc: oofrcpath = os.path.join(os.path.expanduser("~"), ".oof2rc") if os.path.exists(oofrcpath): startupfiles = [StartUpScriptNoLog(oofrcpath)] + startupfiles if thread_enable.query() and not (runtimeflags.text_mode or config.no_gui()): # TODO: Is this still necessary? garbage.disable() # work-around for gtk bug? start_parallel_machine() # start parallel suite (if available) if _rank == 0: if parallel_enable.enabled(): from ooflib.SWIG.common import mpitools _size = mpitools.Size() mpitools.Isend_Bool(thread_enable.enabled(), range(1, _size)) if parallel_enable.enabled(): from ooflib.common.IO import socket2me if config.petsc(): print "Going to InitPETSc" from ooflib.SWIG.engine.PETSc.petsc_solverdriver import InitPETSc InitPETSc(sys.argv) for s in sys.argv: print s start_sockets_Front_End() # Import mainmenu only *after* processing command line options, so # that the options can affect which menus are loaded. global mainmenu from ooflib.common.IO import mainmenu front_end(no_interp) # all non-parallel menu items are executed here. else: # parallel back-end parallel_enable.set(True) # notify back-end of its parallel status # thread status at the back-ends from ooflib.SWIG.common import mpitools thread_enable.set(mpitools.Recv_Bool(0)) if not thread_enable.enabled(): lock.disable_all() if parallel_enable.enabled(): from ooflib.common.IO import socket2me if config.petsc(): print "Going to InitPETSc" from ooflib.SWIG.engine.PETSc.petsc_solverdriver import InitPETSc InitPETSc(sys.argv) for s in sys.argv: print s debug.set_debug_mode() # set for debugging parallel mode from ooflib.common import quit quit.set_quiet() ## back-end exits quietly. start_sockets_Back_End() # socket initialization from ooflib.common import backEnd # import back end machine # The back end shouldn't run the gui! runtimeflags.text_mode = True backEnd.back_end() # back-end awaits for your command
class SkeletonNode(skeletonselectable.SkeletonSelectable, cskeleton.CSkeletonNode): if config.dimension() == 2: def __init__(self, x, y, index): skeletonselectable.SkeletonSelectable.__init__(self, index) cskeleton.CSkeletonNode.__init__(self, x, y) self.dimIndependentInit(index) elif config.dimension() == 3: def __init__(self, x, y, z, points, index): skeletonselectable.SkeletonSelectable.__init__(self, index) cskeleton.CSkeletonNode.__init__(self, x, y, z, points, index) self.dimIndependentInit(index) def moveTo(self, point): # TODO 3D: this could be cleaned up if the elements were stored in C # See note in cskeleton.C cskeleton.CSkeletonNode.moveTo(self, point) for element in self._elements: element.updateVtkCellPoints() def unconstrainedMoveTo(self, point): # TODO 3D: this could be cleaned up if the elements were stored in C # See note in cskeleton.C cskeleton.CSkeletonNode.unconstrainedMoveTo(self, point) for element in self._elements: element.updateVtkCellPoints() def moveBy(self, delta): cskeleton.CSkeletonNode.moveBy(self, delta) for element in self._elements: element.updateVtkCellPoints() def dimIndependentInit(self, index): self._elements = [] self.ID = object_id.ObjectID() # parallel attributes if parallel_enable.enabled(): self._owners = [] # only for the initial Skeleton self._shared_with = [] # except me self._remote_index = {} # procID : remote index def __repr__(self): ## p = self.position() ## return "SkeletonNode#%d(%f, %f)" % (self.index, p.x, p.y) return "SkeletonNode(%d)" % self.index def repr_position(self): return self.position() def getIndex(self): return self.index def destroy(self, skeleton): skeleton.removeNode(self) self.disconnect() del self._elements def active(self, skeleton): return skeleton.MS.activePoint(self.position()) def illegal(self): # A node is illegal if any of its elements are illegal. This # is used when testing possible node motions, so it's assumed # that the node being tested is the one causing the elements # to be illegal. for element in self._elements: if element.illegal(): return 1 return 0 def addElement(self, element): self._elements.append(element) def removeElement(self, skeleton, element): self._elements.remove(element) if not self._elements: self.destroy(skeleton) def getPartners(self): return [] # # TODO throw exception? Better to just not define it. # def addPartner(self,node): # pass def getPartnerPair(self, node): return None def getDirectedPartner(self, direction): return None def aperiodicNeighborElements(self): return self._elements def neighborElements(self): return self.aperiodicNeighborElements() # Two versions of neighborNodes are provided to keep the # interface for SkeletonNode and PeriodicSkeletonNode the same. # Two versions are needed for PeriodicSkeletonNode because in most # contexts we want the neighbors across the boundary, but in # others, such as when drawing rubber band lines, we don't want # the neighbors of the partners. def neighborNodes(self, skeleton): neighborDict = set() for e in self._elements: for nd in e.nodes: if nd is not self: if skeleton.findSegment(nd, self) is not None: neighborDict.add(nd) return neighborDict def aperiodicNeighborNodes(self, skeleton): return self.neighborNodes(skeleton) # "Segments for which I am an endpoint." def localSegments(self, skeleton): result = set() for e in self._elements: for nd in e.nodes: if nd is not self: s = skeleton.findSegment(nd, self) if s: result.add(s) return result # Segments which have only one element. def exteriorSegments(self, skeleton): result = set() for seg in self.localSegments(skeleton): if len(seg.getElements()) == 1: result.add(seg) return result def moveBack(self): cskeleton.CSkeletonNode.moveBack(self) for el in self._elements: el.revertHomogeneity() if config.dimension() == 3: el.updateVtkCellPoints() if config.dimension() == 2: def new_child(self, index): p = self.position() new = self.__class__(p.x, p.y, index) new.copyMobility(self) return new elif config.dimension() == 3: def new_child(self, index, points): p = self.position() new = self.__class__(p.x, p.y, p.z, points, index) new.copyMobility(self) return new #################### # pin and unpin are analogous to select and deselect in the # SkeletonSelectable class. They pin and unpin this node and its # children and parents. The clist and plist args are lists of # trackers corresponding to the children and parents in the # SkeletonContext's stack of skeletons. Some of those Skeletons # may be DeputySkeletons, which share nodes instead of having # parent/child nodes. For those Skeletons the tracker is a # DeputyPinnedNodeTracker instead of a PinnedNodeTracker. def pin(self, clist, plist): self.setPinned(1) here = self.position() self.pinDown(clist, here) self.pinUp(plist, here) def pinDown(self, clist, here): if clist[0].nodePosition(self) == here: clist[0].add(self) if len(clist) > 1: clist[1].pinDown(self, clist[1:], here) def pinUp(self, plist, here): if plist[0].nodePosition(self) == here: plist[0].add(self) if len(plist) > 1: plist[0].pinUp(self, plist[1:], here) def unpin(self, clist, plist): self.setPinned(0) here = self.position() self.unpinDown(clist, here) self.unpinUp(plist, here) def unpinDown(self, clist, here): if clist[0].nodePosition(self) == here: clist[0].remove(self) if len(clist) > 1: clist[1].unpinDown(self, clist[1:], here) def unpinUp(self, plist, here): if plist[0].nodePosition(self) == here: plist[0].remove(self) if len(plist) > 1: plist[0].unpinUp(self, plist[1:], here) ############## ## dominantPixel returns the category of the pixel under the node. def dominantPixel(self, ms): return ms.categoryFromPoint(self.position()) ######## PARALLEL STUFF ######## if parallel_enable.enabled(): def owners(self): return self._owners def nowners(self): return len(self._owners) def addOwner(self, id): if id not in self._owners: self._owners.append(id) def master(self): from ooflib.SWIG.common import mpitools _rank = mpitools.Rank() if self.isShared(): if self._shared_with[0] < _rank: return self._shared_with[0] return _rank def sharesWith(self, id, index): # only when u have a short list! if id not in self._shared_with: self._shared_with.append(id) self._shared_with.sort() self._remote_index[id] = index def sharedWith(self): return self._shared_with def nshared(self): return len(self._shared_with) def remoteIndex(self, id): return self._remote_index[id] def isShared(self): return len(self._shared_with) != 0 def isSharedWith(self, id): return (id in self._shared_with)
def set_communication_cost(pn): if parallel_enable.enabled(): ## back-end + front-end performance.estimate_communication(pn)
class SmoothMovePosition(fiddlenodesbase.FiddleNodesMovePosition): def __call__(self, skeleton, node): if parallel_enable.enabled(): if node.isShared(): # Implicitly, it's mine too. return self.active(skeleton, node) if config.dimension() == 2: avgPos = primitives.Point(0., 0.) elif config.dimension() == 3: avgPos = primitives.Point(0., 0., 0.) nbrNodes = node.neighborNodes(skeleton) for n in nbrNodes: avgPos += skeleton.nodePosition(n) avgPos /= len(nbrNodes) return avgPos # not updated for 3d if parallel_enable.enabled(): def active(self, skeleton, node): # Parallel mode -- owner of shared node from ooflib.SWIG.common import mpitools # Need to get neighboring nodes shared = node.sharedWith() remote_indices = [node.remoteIndex(s) for s in shared] mpitools.Isend_Ints(remote_indices, shared) positions = mpitools.Irecv_DoubleVecs(shared) # [[], [] ...] positions = reduce(lambda x, y: x + y, positions) # [] positions = [[positions[2 * i], positions[2 * i + 1]] for i in range(len(positions) / 2)] # Add my own neighbors nbrNodes = node.neighborNodes(skeleton) positions += [[ skeleton.nodePosition(n).x, skeleton.nodePosition(n).y ] for n in nbrNodes] # Averaging x = 0. y = 0. for p in positions: x += p[0] y += p[1] x /= len(positions) y /= len(positions) return primitives.Point(x, y) def passive(self, skeleton, stopper): # Parallel mode -- share-holder from ooflib.SWIG.common import mpitools _rank = mpitools.Rank() # Getting the node index (local) index = mpitools.Recv_Int(stopper) node = skeleton.getNodeWithIndex(index) # Get the neighbor nodes (but not ones are shared with stoppers, # since they are already accounted for at "stopper".) nbrNodes = node.neighborNodes(skeleton) positions = [] for nd in nbrNodes: if _rank == nd.master(): # my own node positions.append(skeleton.nodePosition(nd).x) positions.append(skeleton.nodePosition(nd).y) mpitools.Send_DoubleVec(positions, stopper)
from ooflib.common.IO import reporter from ooflib.common.IO import placeholder from ooflib.common.IO import xmlmenudump from ooflib.engine import mesh from ooflib.engine import skeletoncontext from ooflib.engine import skeletonmodifier from ooflib.engine.IO import meshparameters from ooflib.engine.IO import output from ooflib.engine.IO import outputDefs import ooflib.SWIG.engine.material #Interface branch from ooflib.common.IO import placeholder from ooflib.engine.IO import meshparameters from ooflib.engine.IO import materialparameter if parallel_enable.enabled(): from ooflib.SWIG.common import mpitools if config.dimension() == 3: import vtk FloatRangeParameter = parameter.FloatRangeParameter IntRangeParameter = parameter.IntRangeParameter AutoNumericParameter = parameter.AutoNumericParameter ################## # Add a parameter to the graphics window's Settings menu, to control # whether or not Mesh Elements with no Material are displayed.
class SnapMovePosition(fiddlenodesbase.FiddleNodesMovePosition): def __call__(self, skeleton, node): if parallel_enable.enabled(): if node.isShared(): # Implicitly, it's mine too. return self.active(skeleton, node) return self.default(skeleton, node) def default(self, skeleton, node): # default transition points point0 = skeleton.nodePosition(node) neighbors = node.neighborNodes(skeleton) transitions = [] for nbr in neighbors: # sgmt = skeleton.findSegment(node, nbr) # used? point1 = skeleton.nodePosition(nbr) transitions.append( skeleton.MS.transitionPointWithPoints(point0, point1)) return transitions def addition(self, skeleton, node, points): point0 = skeleton.nodePosition(node) transitions = [] for p in points: transitions.append(skeleton.MS.transitionPointWithPoints( point0, p)) return transitions # not updated for 3d if parallel_enable.enabled(): def active(self, skeleton, node): from ooflib.SWIG.common import mpitools shared = node.sharedWith() # receiving coords opposite_ends = mpitools.Irecv_DoubleVecs(shared) opposite_ends = reduce(lambda x, y: x + y, opposite_ends) # create a list of points end_points = [] for i in range(len(opposite_ends) / 2): x = opposite_ends[2 * i] y = opposite_ends[2 * i + 1] end_points.append(primitives.Point(x, y)) # move candidates move_candidates = self.default(skeleton, node) # list of points move_candidates += self.addition(skeleton, node, end_points) # returns non-trivial ones return [mc for mc in move_candidates if mc] def passive(self, skeleton, node, stopper): from ooflib.SWIG.common import mpitools _rank = mpitools.Rank() # now, find all neighboring nodes neighbors = node.neighborNodes(skeleton) # among these, collect ones of which I'm the master. neighbors = [n for n in neighbors if _rank == n.master()] if neighbors: coords = [[ skeleton.nodePosition(n).x, skeleton.nodePosition(n).y ] for n in neighbors] coords = reduce(lambda x, y: x + y, coords) else: coords = [] # send the nodes mpitools.Send_DoubleVec(coords, stopper)