def setupPatchNames(self): print('Populating createPatchDict to update BC names') import CfdMeshTools # Init in case not meshed yet CfdMeshTools.CfdMeshTools(self.mesh_obj) settings = self.settings settings['createPatches'] = {} bc_group = self.bc_group mobj = self.mesh_obj # Make list of list of all boundary references for their corresponding boundary boundary_ref_lists = [] for bc_id, bc_obj in enumerate(bc_group): boundary_ref_lists.append(bc_obj.References) # Match them up with faces in the meshed part matched_faces = CfdTools.matchFacesToTargetShape( boundary_ref_lists, mobj.Part.Shape) bc_lists = [] for bc in bc_group: bc_lists.append([]) for i in range(len(matched_faces)): if matched_faces[i]: nb, bref = matched_faces[i][0] bc_lists[nb].append(mobj.ShapeFaceNames[i]) for k in range(len(matched_faces[i]) - 1): nb2, bref2 = matched_faces[i][k + 1] if nb2 != nb: cfdMessage( "Boundary '{}' reference {}:{} also assigned as " "boundary '{}' reference {}:{}\n".format( bc_group[nb].Label, bref[0], bref[1], bc_group[nb2].Label, bref2[0], bref2[1])) for bc_id, bc_obj in enumerate(bc_group): bcType = bc_obj.BoundaryType bcSubType = bc_obj.BoundarySubType patchType = CfdTools.getPatchType(bcType, bcSubType) settings['createPatches'][bc_obj.Label] = { 'PatchNamesList': tuple(bc_lists[bc_id] ), # Tuple used so that case writer outputs as an array 'PatchType': patchType } if self.mesh_obj.MeshUtility == 'snappyHexMesh': for regionObj in CfdTools.getMeshRefinementObjs(self.mesh_obj): if regionObj.Baffle: settings['createPatchesFromSnappyBaffles'] = True if settings['createPatchesFromSnappyBaffles']: settings['createPatchesSnappyBaffles'] = {} # TODO Still need to include an error checker in the event that # an internal baffle is created using snappy but is not linked up # with a baffle boundary condition (as in there is no baffle boundary condition which # corresponds. Currently openfoam will throw a contextually # confusing error (only that the boundary does not exist). The primary difficulty with such a checker is # that it is possible to define a boundary face as a baffle, which will be overridden # by the actual boundary name and therefore won't exist anymore. for bc_id, bc_obj in enumerate(bc_group): bcType = bc_obj.BoundaryType if bcType == "baffle": tempBaffleList = [] tempBaffleListSlave = [] for regionObj in self.mesh_obj.Group: if hasattr(regionObj, "Proxy") and \ isinstance(regionObj.Proxy, CfdMeshRefinement._CfdMeshRefinement): # print regionObj.Name if regionObj.Baffle: for sub in regionObj.References: # print sub[0].Name elems = sub[1] elt = FreeCAD.ActiveDocument.getObject( sub[0]).Shape.getElement(elems) if elt.ShapeType == 'Face': bcFacesList = bc_obj.Shape.Faces for bf in bcFacesList: isSameGeo = CfdTools.isSameGeometry( bf, elt) if isSameGeo: tempBaffleList.append( regionObj.Name + sub[0] + elems) tempBaffleListSlave.append( regionObj.Name + sub[0] + elems + "_slave") settings['createPatchesSnappyBaffles'][bc_obj.Label] = { "PatchNamesList": tuple(tempBaffleList), "PatchNamesListSlave": tuple(tempBaffleListSlave) } # Add default faces flagName = False def_bc_list = [] for i in range(len(matched_faces)): if not matched_faces[i]: def_bc_list.append(mobj.ShapeFaceNames[i]) flagName = True if flagName: settings['createPatches']['defaultFaces'] = { 'PatchNamesList': tuple(def_bc_list), 'PatchType': "patch" }
def writeCase(self, progressCallback=None): """ writeCase() will collect case settings, and finally build a runnable case. """ cfdMessage("Start to write case to folder {}\n".format( self.working_dir)) if not os.path.exists(self.working_dir): raise IOError("Path " + self.solver_obj.working_dir + " does not exist.") # Perform initialisation here rather than __init__ in case of path changes self.case_folder = os.path.join(self.working_dir, self.solver_obj.InputCaseName) self.case_folder = os.path.expanduser(os.path.abspath( self.case_folder)) self.mesh_file_name = os.path.join(self.case_folder, self.solver_obj.InputCaseName, u".unv") self.template_path = os.path.join(CfdTools.get_module_path(), "data", "defaults") # Collect settings into single dictionary if not self.mesh_obj: raise RuntimeError("No mesh object found in analysis") phys_settings = CfdTools.propsToDict(self.physics_model) # TODO: Make sure boundary labels are unique and valid self.settings = { 'physics': phys_settings, 'fluidProperties': [], # Order is important, so use a list 'initialValues': CfdTools.propsToDict(self.initial_conditions), 'boundaries': dict((b.Label, CfdTools.propsToDict(b)) for b in self.bc_group), 'bafflesPresent': self.bafflesPresent(), 'porousZones': {}, 'porousZonesPresent': False, 'initialisationZones': { o.Label: CfdTools.propsToDict(o) for o in self.initialisationZone_objs }, 'initialisationZonesPresent': len(self.initialisationZone_objs) > 0, 'zones': { o.Label: { 'PartNameList': tuple(r[0] for r in o.References) } for o in self.zone_objs }, 'zonesPresent': len(self.zone_objs) > 0, 'meshType': self.mesh_obj.Proxy.Type, 'meshDimension': self.mesh_obj.ElementDimension, 'meshDir': "../" + self.mesh_obj.CaseName, 'solver': CfdTools.propsToDict(self.solver_obj), 'system': {}, 'runChangeDictionary': False } self.processSystemSettings() self.processSolverSettings() self.processFluidProperties() self.processBoundaryConditions() self.processInitialConditions() self.clearCase() self.exportZoneStlSurfaces() if self.porousZone_objs: self.processPorousZoneProperties() self.processInitialisationZoneProperties() self.settings['createPatchesFromSnappyBaffles'] = False cfdMessage("Matching boundary conditions ...\n") if progressCallback: progressCallback("Matching boundary conditions ...") self.setupPatchNames() TemplateBuilder.TemplateBuilder(self.case_folder, self.template_path, self.settings) # Update Allrun permission - will fail silently on Windows fname = os.path.join(self.case_folder, "Allrun") import stat s = os.stat(fname) os.chmod(fname, s.st_mode | stat.S_IEXEC) cfdMessage("Successfully wrote case to folder {}\n".format( self.working_dir)) return True
def setupPatchNames(self): print('Populating createPatchDict to update BC names') import CfdMeshTools # Init in case not meshed yet CfdMeshTools.CfdMeshTools(self.mesh_obj) settings = self.settings settings['createPatches'] = {} bc_group = self.bc_group mobj = self.mesh_obj # Make list of all boundary references boundary_face_list = [] for bc_id, bc_obj in enumerate(bc_group): for ref in bc_obj.References: obj = FreeCAD.ActiveDocument.getObject(ref[0]) if not obj: raise RuntimeError( "Referenced object '{}' not found - object may " "have been deleted".format(ref[0])) try: bf = obj.Shape.getElement(ref[1]) except Part.OCCError: raise RuntimeError( "Referenced face '{}:{}' not found - face may " "have been deleted".format(ref[0], ref[1])) boundary_face_list.append((bf, (bc_id, ref))) # Make list of all faces in meshed shape with original index mesh_face_list = list( zip(mobj.Part.Shape.Faces, range(len(mobj.Part.Shape.Faces)))) # Match them up matched_faces = CfdTools.matchFaces(boundary_face_list, mesh_face_list) # Check for and filter duplicates match_per_shape_face = [-1] * len(mesh_face_list) for k in range(len(matched_faces)): match = matched_faces[k][1] prev_k = match_per_shape_face[match] if prev_k >= 0: nb, bref = matched_faces[k][0] nb2, bref2 = matched_faces[prev_k][0] cfdMessage( "Boundary '{}' reference {}:{} also assigned as " "boundary '{}' reference {}:{} - ignoring duplicate\n". format(bc_group[nb].Label, bref[0], bref[1], bc_group[nb2].Label, bref2[0], bref2[1])) else: match_per_shape_face[match] = k bc_lists = [[] for g in bc_group] for i in range(len(match_per_shape_face)): k = match_per_shape_face[i] if k >= 0: nb, bref = matched_faces[k][0] bc_lists[nb].append(mobj.ShapeFaceNames[i]) for bc_id, bc_obj in enumerate(bc_group): bcType = bc_obj.BoundaryType bcSubType = bc_obj.BoundarySubType patchType = CfdTools.getPatchType(bcType, bcSubType) settings['createPatches'][bc_obj.Label] = { 'PatchNamesList': tuple(bc_lists[bc_id] ), # Tuple used so that case writer outputs as an array 'PatchType': patchType } if self.mesh_obj.MeshUtility == 'snappyHexMesh': for regionObj in CfdTools.getMeshRefinementObjs(self.mesh_obj): if regionObj.Baffle: settings['createPatchesFromSnappyBaffles'] = True if settings['createPatchesFromSnappyBaffles']: settings['createPatchesSnappyBaffles'] = {} baffle_geoms = [] for regionObj in self.mesh_obj.Group: if hasattr(regionObj, "Proxy") and isinstance( regionObj.Proxy, CfdMeshRefinement._CfdMeshRefinement): if regionObj.Baffle: for sub in regionObj.References: elems = sub[1] elt = FreeCAD.ActiveDocument.getObject( sub[0]).Shape.getElement(elems) if elt.ShapeType == 'Face': baffle_geoms.append( (elt, (regionObj.Name + sub[0] + elems, len(baffle_geoms)))) print(boundary_face_list) matched_baffle_faces = CfdTools.matchFaces(boundary_face_list, baffle_geoms) # Check for duplicates match_per_baffle_face = [-1] * len(baffle_geoms) for matchi, mf in enumerate(matched_baffle_faces): if match_per_baffle_face[mf[1][1]] > -1: cfdMessage("Baffle face matches to boundary " + mf[0][1] + " and " + matched_baffle_faces[ match_per_baffle_face[mf[1][1]]][0][1] + " - discarding duplicate") else: match_per_baffle_face[mf[1][1]] = matchi for bfi, mi in enumerate(match_per_baffle_face): if mi > -1: mf = matched_baffle_faces[mi] bc_label = bc_group[mf[0][0]].Label settings['createPatchesSnappyBaffles'][bc_label] = \ settings['createPatchesSnappyBaffles'].get(bc_label, {}) settings['createPatchesSnappyBaffles'][bc_label]['PatchNamesList'] = \ settings['createPatchesSnappyBaffles'][bc_label].get('PatchNamesList', ()) + \ (mf[1][0],) settings['createPatchesSnappyBaffles'][bc_label]['PatchNamesListSlave'] = \ settings['createPatchesSnappyBaffles'][bc_label].get('PatchNamesListSlave', ()) + \ ((mf[1][0]+"_slave"),) else: cfdMessage( "No boundary condition specified for baffle face " + baffle_geoms[bfi][1][0]) # Add default faces flagName = False def_bc_list = [] for i in range(len(match_per_shape_face)): if match_per_shape_face[i] < 0: def_bc_list.append(mobj.ShapeFaceNames[i]) flagName = True if flagName: settings['createPatches']['defaultFaces'] = { 'PatchNamesList': tuple(def_bc_list), 'PatchType': "patch" }
def writeCase(self): """ writeCase() will collect case settings, and finally build a runnable case. """ cfdMessage("Start to write case to folder {}\n".format( self.working_dir)) if not os.path.exists(self.working_dir): raise IOError("Path " + self.solver_obj.working_dir + " does not exist.") # Perform initialisation here rather than __init__ in case of path changes self.case_folder = os.path.join(self.working_dir, self.solver_obj.InputCaseName) self.case_folder = os.path.expanduser(os.path.abspath( self.case_folder)) self.mesh_file_name = os.path.join(self.case_folder, self.solver_obj.InputCaseName, u".unv") self.template_path = os.path.join(CfdTools.get_module_path(), "data", "defaults") solverSettingsDict = CfdTools.getSolverSettings(self.solver_obj) # Collect settings into single dictionary if not self.mesh_obj: raise RuntimeError("No mesh object found in analysis") phys_settings = dict( zip(self.physics_model.PropertiesList, (getattr(self.physics_model, prop) for prop in self.physics_model.PropertiesList))) if 'gx' in phys_settings: phys_settings['gx'] = Units.Quantity( phys_settings['gx']).getValueAs('m/s^2') phys_settings['gy'] = Units.Quantity( phys_settings['gy']).getValueAs('m/s^2') phys_settings['gz'] = Units.Quantity( phys_settings['gz']).getValueAs('m/s^2') self.settings = { 'physics': phys_settings, 'fluidProperties': [], # Order is important, so use a list 'initialValues': self.initial_conditions, 'boundaries': dict((b.Label, b.BoundarySettings) for b in self.bc_group), 'bafflesPresent': self.bafflesPresent(), 'porousZones': {}, 'porousZonesPresent': False, 'initialisationZones': { o.Label: o.initialisationZoneProperties for o in self.initialisationZone_objs }, 'initialisationZonesPresent': len(self.initialisationZone_objs) > 0, 'zones': { o.Label: { 'PartNameList': tuple(o.partNameList) } for o in self.zone_objs }, 'zonesPresent': len(self.zone_objs) > 0, 'meshType': self.mesh_obj.Proxy.Type, 'meshDimension': self.mesh_obj.ElementDimension, 'solver': solverSettingsDict, 'system': {}, 'runChangeDictionary': False } self.processSystemSettings() self.processSolverSettings() self.processFluidProperties() self.processBoundaryConditions() self.processInitialConditions() self.clearCase() self.exportZoneStlSurfaces() if self.porousZone_objs: self.processPorousZoneProperties() self.processInitialisationZoneProperties() self.settings['createPatchesFromSnappyBaffles'] = False cfdMessage("Matching boundary conditions ...\n") self.setupPatchNames() TemplateBuilder.TemplateBuilder(self.case_folder, self.template_path, self.settings) self.writeMesh() # Update Allrun permission - will fail silently on Windows fname = os.path.join(self.case_folder, "Allrun") import stat s = os.stat(fname) os.chmod(fname, s.st_mode | stat.S_IEXEC) # Move mesh files, after being edited, to polyMesh.org CfdTools.movePolyMesh(self.case_folder) cfdMessage("Successfully wrote {} case to folder {}\n".format( self.solver_obj.SolverName, self.working_dir)) return True
def writeCase(self): """ writeCase() will collect case settings, and finally build a runnable case. """ cfdMessage("Start to write case to folder {}\n".format(self.solver_obj.WorkingDir)) cwd = os.curdir if not os.path.exists(self.solver_obj.WorkingDir): raise IOError("Path " + self.solver_obj.WorkingDir + " does not exist.") os.chdir(self.solver_obj.WorkingDir) try: # Make sure we restore cwd after exception here # Perform initialisation here rather than __init__ in case of path changes self.case_folder = os.path.join(self.solver_obj.WorkingDir, self.solver_obj.InputCaseName) self.case_folder = os.path.expanduser(os.path.abspath(self.case_folder)) self.mesh_file_name = os.path.join(self.case_folder, self.solver_obj.InputCaseName, u".unv") self.template_path = os.path.join(CfdTools.get_module_path(), "data", "defaults") solverSettingsDict = CfdTools.getSolverSettings(self.solver_obj) self.check2DConversion() # Collect settings into single dictionary if not self.mesh_obj: raise RuntimeError("No mesh object found in analysis") self.settings = { 'physics': self.physics_model, 'fluidProperties': [], # Order is important, so use a list 'initialValues': self.initial_conditions, 'boundaries': dict((b.Label, b.BoundarySettings) for b in self.bc_group), 'bafflesPresent': self.bafflesPresent(), 'porousZones': {}, 'porousZonesPresent': False, 'initialisationZones': {o.Label: o.initialisationZoneProperties for o in self.initialisationZone_objs}, 'initialisationZonesPresent': len(self.initialisationZone_objs) > 0, 'zones': {o.Label: {'PartNameList': tuple(o.partNameList)} for o in self.zone_objs}, 'zonesPresent': len(self.zone_objs) > 0, 'meshType': self.mesh_obj.Proxy.Type, 'solver': solverSettingsDict, 'system': {}, 'runChangeDictionary':False } self.processSystemSettings() self.processSolverSettings() self.processFluidProperties() self.processBoundaryConditions() self.processInitialConditions() self.clearCase() self.exportZoneStlSurfaces() if self.porousZone_objs: self.processPorousZoneProperties() self.processInitialisationZoneProperties() self.settings['createPatchesFromSnappyBaffles'] = False if self.mesh_obj.Proxy.Type == "CfdMeshCart": # Cut-cell Cartesian self.setupPatchNames() if self.meshConvertedTo2D and self.mesh_obj.Proxy.Type == "Fem::FemMeshGmsh": self.settings['runChangeDictionary'] = True TemplateBuilder.TemplateBuilder(self.case_folder, self.template_path, self.settings) self.writeMesh() # Update Allrun permission - will fail silently on Windows fname = os.path.join(self.case_folder, "Allrun") import stat s = os.stat(fname) os.chmod(fname, s.st_mode | stat.S_IEXEC) # Move mesh files, after being edited, to polyMesh.org CfdTools.movePolyMesh(self.case_folder) except: raise finally: os.chdir(cwd) # Restore working dir cfdMessage("Successfully wrote {} case to folder {}\n".format( self.solver_obj.SolverName, self.solver_obj.WorkingDir)) return True