def processSystemSettings(self): system_settings = self.settings['system'] system_settings['FoamRuntime'] = CfdTools.getFoamRuntime() system_settings['CasePath'] = self.case_folder system_settings['FoamPath'] = CfdTools.getFoamDir() if CfdTools.getFoamRuntime() != 'WindowsDocker': system_settings['TranslatedFoamPath'] = CfdTools.translatePath(CfdTools.getFoamDir())
def downloadHisa(self): filename = self.download(self.hisa_url, HISA_FILE_EXT, "HiSA") if CfdTools.getFoamRuntime() == "MinGW": self.user_dir = None self.signals.status.emit("Installing HiSA...") CfdTools.runFoamCommand( '{{ mkdir -p "$FOAM_APPBIN" && cd "$FOAM_APPBIN" && unzip -o "{}"; }}' .format(CfdTools.translatePath(filename))) else: self.user_dir = CfdTools.runFoamCommand( "echo $WM_PROJECT_USER_DIR").rstrip().split('\n')[-1] # We can't reverse-translate the path for docker since it sits inside the container. Just report it as such. if CfdTools.getFoamRuntime() != 'WindowsDocker': self.user_dir = CfdTools.reverseTranslatePath(self.user_dir) self.signals.status.emit("Extracting HiSA...") if CfdTools.getFoamRuntime() == 'WindowsDocker': from zipfile import ZipFile with ZipFile(filename, 'r') as zip: with tempfile.TemporaryDirectory() as tempdir: zip.extractall(path=tempdir) CfdTools.runFoamCommand( '{{ mkdir -p "$WM_PROJECT_USER_DIR" && cp -r "{}" "$WM_PROJECT_USER_DIR/"; }}' .format( CfdTools.translatePath( os.path.join(tempdir, HISA_FILE_BASE)))) else: CfdTools.runFoamCommand( '{{ mkdir -p "$WM_PROJECT_USER_DIR" && cd "$WM_PROJECT_USER_DIR" && ( rm -r {}; unzip -o "{}"; ); }}' .format(HISA_FILE_BASE, CfdTools.translatePath(filename)))
def threadFinished(self, status): if self.thread.task == DOWNLOAD_CFMESH: if status: self.consoleMessage("Download completed") if CfdTools.getFoamRuntime() != "MinGW": user_dir = self.thread.user_dir self.consoleMessage( "Building cfMesh. Lengthy process - please wait...") self.consoleMessage("Log file: {}/{}/log.Allwmake".format( user_dir, CFMESH_FILE_BASE)) if CfdTools.getFoamRuntime() == 'WindowsDocker': # There seem to be issues when using multi processors to build in docker self.install_process = CfdTools.startFoamApplication( "export WM_NCOMPPROCS=1; ./Allwmake", "$WM_PROJECT_USER_DIR/" + CFMESH_FILE_BASE, 'log.Allwmake', self.installFinished) else: self.install_process = CfdTools.startFoamApplication( "export WM_NCOMPPROCS=`nproc`; ./Allwmake", "$WM_PROJECT_USER_DIR/" + CFMESH_FILE_BASE, 'log.Allwmake', self.installFinished) # Reset foam dir for now in case the user presses 'Cancel' CfdTools.setFoamDir(self.initial_foam_dir) else: self.consoleMessage("Download unsuccessful") elif self.thread.task == DOWNLOAD_HISA: if status: self.consoleMessage("Download completed") if CfdTools.getFoamRuntime() != "MinGW": user_dir = self.thread.user_dir self.consoleMessage("Building HiSA. Please wait...") self.consoleMessage("Log file: {}/{}/log.Allwmake".format( user_dir, HISA_FILE_BASE)) if CfdTools.getFoamRuntime() == 'WindowsDocker': # There seem to be issues when using multi processors to build in docker self.install_process = CfdTools.startFoamApplication( "export WM_NCOMPPROCS=1; ./Allwmake", "$WM_PROJECT_USER_DIR/" + HISA_FILE_BASE, 'log.Allwmake', self.installFinished) else: self.install_process = CfdTools.startFoamApplication( "export WM_NCOMPPROCS=`nproc`; ./Allwmake", "$WM_PROJECT_USER_DIR/" + HISA_FILE_BASE, 'log.Allwmake', self.installFinished) # Reset foam dir for now in case the user presses 'Cancel' CfdTools.setFoamDir(self.initial_foam_dir) else: self.consoleMessage("Download unsuccessful") self.thread = None
def openParaview(self): self.Start = time.time() QApplication.setOverrideCursor(Qt.WaitCursor) script_name = os.path.abspath( os.path.join(self.working_dir, self.solver_object.InputCaseName, "pvScript.py")) paraview_cmd = "paraview" # If using blueCFD, use paraview supplied if CfdTools.getFoamRuntime() == 'BlueCFD': paraview_cmd = '{}\\..\\AddOns\\ParaView\\bin\\paraview.exe'.format( CfdTools.getFoamDir()) # Otherwise, the command 'paraview' must be in the path. Possibly make path user-settable. # Test to see if it exists, as the exception thrown is cryptic on Windows if it doesn't import distutils.spawn if distutils.spawn.find_executable(paraview_cmd) is None: raise IOError("Paraview executable " + paraview_cmd + " not found in path.") arg = '--script={}'.format(script_name) self.consoleMessage("Running " + paraview_cmd + " " + arg) self.open_paraview.start(paraview_cmd, [arg]) if self.open_paraview.waitForStarted(): self.consoleMessage("Paraview started") else: self.consoleMessage("Error starting paraview") QApplication.restoreOverrideCursor()
def threadFinished(self, status): if self.thread.task == DOWNLOAD_CFMESH: if status: self.consoleMessage("Download completed") user_dir = self.thread.user_dir self.consoleMessage( "Building cfMesh. Lengthy process - please wait...") if CfdTools.getFoamRuntime() == "BlueCFD": script_name = "buildCfMeshOnBlueCFD.sh" self.consoleMessage("Log file: {}\\log.{}".format( user_dir, script_name)) TemplateBuilder.TemplateBuilder( user_dir, os.path.join(CfdTools.get_module_path(), 'data', 'foamUserDir'), {'cfMeshDirectory': CFMESH_FILE_BASE}) self.install_process = CfdTools.startFoamApplication( "./" + script_name, "$WM_PROJECT_USER_DIR", self.installFinished) else: self.consoleMessage("Log file: {}/{}/log.Allwmake".format( user_dir, CFMESH_FILE_BASE)) self.install_process = CfdTools.startFoamApplication( "./Allwmake", "$WM_PROJECT_USER_DIR/" + CFMESH_FILE_BASE, self.installFinished) # Reset foam dir for now in case the user presses 'Cancel' CfdTools.setFoamDir(self.initial_foam_dir) else: self.consoleMessage("Download unsuccessful") self.thread = None
def threadFinished(self, status): if self.thread.task == DEPENDENCY_CHECK: QApplication.restoreOverrideCursor() elif self.thread.task == DOWNLOAD_CFMESH: if status: self.consoleMessage("Download completed") user_dir = self.thread.user_dir self.consoleMessage( "Building cfMesh. Lengthy process - please wait...") if CfdTools.getFoamRuntime() == "BlueCFD": script_name = "buildCfMeshOnBlueCFD.sh" self.consoleMessage("Log file: {}\\log.{}".format( user_dir, script_name)) shutil.copy( os.path.join(CfdTools.get_module_path(), 'data', script_name), os.path.join(user_dir, script_name)) self.install_process = CfdTools.startFoamApplication( "./" + script_name, "$WM_PROJECT_USER_DIR", self.installFinished) else: self.consoleMessage("Log file: {}/{}/log.Allwmake".format( user_dir, CFMESH_FILE_BASE)) self.install_process = CfdTools.startFoamApplication( "./Allwmake", "$WM_PROJECT_USER_DIR/" + CFMESH_FILE_BASE, self.installFinished) else: self.consoleMessage("Download unsuccessful")
def __init__(self, analysis=None, solver=None): super(CfdRunnableFoam, self).__init__(analysis, solver) self.writer = CfdCaseWriterFoam.CfdCaseWriterFoam(self.analysis) # Set default windows executable to gnuplot instead of older pgnuplot import platform if platform.system() == 'Windows': Gnuplot.GnuplotOpts.gnuplot_command = 'gnuplot.exe' gnuplot_cmd = Gnuplot.GnuplotOpts.gnuplot_command # For blueCFD, use the supplied Gnuplot if CfdTools.getFoamRuntime() == 'BlueCFD': gnuplot_cmd = CfdTools.getFoamDir() gnuplot_cmd = '{}\\..\\AddOns\\gnuplot\\bin\\gnuplot.exe'.format( gnuplot_cmd) Gnuplot.GnuplotOpts.gnuplot_command = '"{}"'.format(gnuplot_cmd) # Otherwise, the command 'gnuplot' must be in the path. Possibly make path user-settable. # Test to see if it exists, as the exception thrown is cryptic on Windows if it doesn't import distutils.spawn if distutils.spawn.find_executable(gnuplot_cmd) is None: raise IOError("Gnuplot executable " + gnuplot_cmd + " not found in path.") self.g = Gnuplot.Gnuplot() self.UxResiduals = [1] self.UyResiduals = [1] self.UzResiduals = [1] self.pResiduals = [1] self.niter = 0 self.print_next_error_lines = 0 self.print_next_error_file = False
def createMeshScript(self, run_parallel, mesher_name, num_proc, cartMethod): print("Create Allmesh script ") fname = self.meshCaseDir + os.path.sep + "Allmesh" # Replace if os.path.exists(fname): print("Warning: Overwrite existing Allmesh script and log files.") os.remove(os.path.join(self.meshCaseDir, "log.surfaceFeatureEdges")) os.remove(os.path.join(self.meshCaseDir, "log.cartesianMesh")) with open(fname, 'w+') as f: source = "" triSurfaceDir = os.path.join('constant', 'triSurface') if not CfdTools.getFoamRuntime( ) == "BlueCFD": # Runs inside own environment - no need to source source = CfdTools.readTemplate( os.path.join(self.templatePath, "_helperFiles", "AllrunSource"), {"FOAMDIR": CfdTools.translatePath(CfdTools.getFoamDir())}) head = CfdTools.readTemplate( os.path.join(self.templatePath, "_helperFiles", "AllmeshPreamble"), {"SOURCE": source}) f.write(head) if cartMethod == 'cfMesh' and mesher_name == 'cartesianMesh': f.write('# Extract feature edges\n') f.write( 'runCommand surfaceFeatureEdges -angle 60 "{}_Geometry.stl" "{}_Geometry.fms"' '\n'.format( os.path.join(triSurfaceDir, self.part_obj.Name), self.part_obj.Name)) f.write('\n') f.write('runCommand cartesianMesh\n') f.write('\n') elif cartMethod == 'snappyHexMesh': f.write('runCommand blockMesh \n') f.write('runCommand surfaceFeatureExtract \n') f.write('runCommand snappyHexMesh -overwrite\n') f.write('runCommand surfaceToPatch constant/triSurface/' + self.part_obj.Name + '_Geometry.stl \n') # Create stl of FOAM mesh outside (in mm) to view the object in FreeCAD. f.write('runCommand surfaceMeshTriangulate mesh_outside.stl\n') f.write( 'runCommand surfaceTransformPoints -scale "(1000 1000 1000)"' + ' mesh_outside.stl mesh_outside.stl\n') f.write('\n') import stat s = os.stat(fname) os.chmod(fname, s.st_mode | stat.S_IEXEC ) # Update Allmesh permission - will fail silently on windows
def threadFinished(self, status): if self.thread.task == DEPENDENCY_CHECK: QApplication.restoreOverrideCursor() elif self.thread.task == DOWNLOAD_GNUPLOTPY: self.consoleMessage("Attempting to install Gnuplot-py package:") if platform.system() == 'Windows': python_exe = os.path.join(FreeCAD.getHomePath(), 'bin', 'python.exe') else: python_exe = 'python' cmd = [python_exe, '-u', 'setup.py', 'install'] working_dir = os.path.join(tempfile.gettempdir(), GNUPLOTPY_FILE_BASE) self.install_process = CfdConsoleProcess.CfdConsoleProcess( finishedHook=self.installFinished) print("Running {} in {}".format(' '.join(cmd), working_dir)) self.install_process.start(cmd, working_dir=working_dir) if not self.install_process.waitForStarted(): self.consoleMessage("Unable to run command " + ' '.join(cmd), '#FF0000') elif self.thread.task == DOWNLOAD_CFMESH: if status: self.consoleMessage("Download completed") user_dir = self.thread.user_dir self.consoleMessage( "Building cfMesh. Lengthy process - please wait...") if CfdTools.getFoamRuntime() == "BlueCFD": script_name = "buildCfMeshOnBlueCFD.sh" self.consoleMessage("Log file: {}\\log.{}".format( user_dir, script_name)) shutil.copy( os.path.join(CfdTools.get_module_path(), 'data', script_name), os.path.join(user_dir, script_name)) self.install_process = CfdTools.startFoamApplication( "./" + script_name, "$WM_PROJECT_USER_DIR", self.installFinished) else: self.consoleMessage("Log file: {}/{}/log.Allwmake".format( user_dir, CFMESH_FILE_BASE)) self.install_process = CfdTools.startFoamApplication( "./Allwmake", "$WM_PROJECT_USER_DIR/" + CFMESH_FILE_BASE, self.installFinished) else: self.consoleMessage("Download unsuccessful")
def testGetRuntime(self, disable_exception=True): """ Set the foam dir temporarily and see if we can detect the runtime """ prefs = CfdTools.getPreferencesLocation() prev_foam_dir = FreeCAD.ParamGet(prefs).GetString( "InstallationPath", "") CfdTools.setFoamDir(self.foam_dir) try: runtime = CfdTools.getFoamRuntime() except IOError as e: runtime = None if not disable_exception: raise CfdTools.setFoamDir(prev_foam_dir) return runtime
def openParaview(self): self.Start = time.time() QApplication.setOverrideCursor(Qt.WaitCursor) paraview_cmd = "paraview" # If using blueCFD, use paraview supplied if CfdTools.getFoamRuntime() == 'BlueCFD': paraview_cmd = '{}\\..\\AddOns\\ParaView\\bin\\paraview.exe'.format(CfdTools.getFoamDir()) # Otherwise, the command 'paraview' must be in the path. Possibly make path user-settable. # Test to see if it exists, as the exception thrown is cryptic on Windows if it doesn't import distutils.spawn if distutils.spawn.find_executable(paraview_cmd) is None: raise IOError("Paraview executable " + paraview_cmd + " not found in path.") self.paraviewScriptName = os.path.join(self.meshCaseDir, 'pvScriptMesh.py') arg = '--script={}'.format(self.paraviewScriptName) self.console_log("Running " + paraview_cmd + " " +arg) self.open_paraview.start(paraview_cmd, [arg]) QApplication.restoreOverrideCursor()
def writeMeshCase(self): """ Collect case settings, and finally build a runnable case. """ CfdTools.cfdMessage( "Populating mesh dictionaries in folder {}\n".format( self.meshCaseDir)) if self.mesh_obj.MeshUtility == "cfMesh": self.cf_settings['ClMax'] = self.clmax * self.scale if len(self.cf_settings['BoundaryLayers']) > 0: self.cf_settings['BoundaryLayerPresent'] = True else: self.cf_settings['BoundaryLayerPresent'] = False if len(self.cf_settings["InternalRegions"]) > 0: self.cf_settings['InternalRefinementRegionsPresent'] = True else: self.cf_settings['InternalRefinementRegionsPresent'] = False elif self.mesh_obj.MeshUtility == "snappyHexMesh": bound_box = self.part_obj.Shape.BoundBox bC = 5 # Number of background mesh buffer cells x_min = (bound_box.XMin - bC * self.clmax) * self.scale x_max = (bound_box.XMax + bC * self.clmax) * self.scale y_min = (bound_box.YMin - bC * self.clmax) * self.scale y_max = (bound_box.YMax + bC * self.clmax) * self.scale z_min = (bound_box.ZMin - bC * self.clmax) * self.scale z_max = (bound_box.ZMax + bC * self.clmax) * self.scale cells_x = int(math.ceil(bound_box.XLength / self.clmax) + 2 * bC) cells_y = int(math.ceil(bound_box.YLength / self.clmax) + 2 * bC) cells_z = int(math.ceil(bound_box.ZLength / self.clmax) + 2 * bC) snappy_settings = self.snappy_settings snappy_settings['BlockMesh'] = { "xMin": x_min, "xMax": x_max, "yMin": y_min, "yMax": y_max, "zMin": z_min, "zMax": z_max, "cellsX": cells_x, "cellsY": cells_y, "cellsZ": cells_z } inside_x = Units.Quantity( self.mesh_obj.PointInMesh.get('x')).Value * self.scale inside_y = Units.Quantity( self.mesh_obj.PointInMesh.get('y')).Value * self.scale inside_z = Units.Quantity( self.mesh_obj.PointInMesh.get('z')).Value * self.scale shape_face_names_list = [] for i in self.mesh_obj.ShapeFaceNames: shape_face_names_list.append(i) snappy_settings['ShapeFaceNames'] = tuple(shape_face_names_list) snappy_settings[ 'EdgeRefinementLevel'] = CfdTools.relLenToRefinementLevel( self.mesh_obj.EdgeRefinement) snappy_settings['PointInMesh'] = { "x": inside_x, "y": inside_y, "z": inside_z } snappy_settings[ 'CellsBetweenLevels'] = self.mesh_obj.CellsBetweenLevels if len(self.snappy_settings["InternalRegions"]) > 0: self.snappy_settings['InternalRefinementRegionsPresent'] = True else: self.snappy_settings[ 'InternalRefinementRegionsPresent'] = False elif self.mesh_obj.MeshUtility == "gmsh": if platform.system() == "Windows": exe = os.path.join(FreeCAD.getHomePath(), 'bin', 'gmsh.exe') else: exe = subprocess.check_output( ["which", "gmsh"], universal_newlines=True).rstrip('\n') self.gmsh_settings['Executable'] = CfdTools.translatePath(exe) self.gmsh_settings['ShapeFile'] = self.temp_file_shape self.gmsh_settings['HasLengthMap'] = False if self.ele_length_map: self.gmsh_settings['HasLengthMap'] = True self.gmsh_settings['LengthMap'] = self.ele_length_map self.gmsh_settings['NodeMap'] = {} for e in self.ele_length_map: ele_nodes = (''.join( (str(n + 1) + ', ') for n in self.ele_node_map[e])).rstrip(', ') self.gmsh_settings['NodeMap'][e] = ele_nodes self.gmsh_settings['ClMax'] = self.clmax self.gmsh_settings['ClMin'] = self.clmin sols = (''.join( (str(n + 1) + ', ') for n in range(len(self.mesh_obj.Part.Shape.Solids))) ).rstrip(', ') self.gmsh_settings['Solids'] = sols self.gmsh_settings['BoundaryFaceMap'] = {} # Write one boundary per face for i in range(len(self.mesh_obj.Part.Shape.Faces)): self.gmsh_settings['BoundaryFaceMap']['face' + str(i)] = i + 1 self.gmsh_settings['MeshFile'] = self.temp_file_mesh # Perform initialisation here rather than __init__ in case of path changes self.template_path = os.path.join(CfdTools.get_module_path(), "data", "defaultsMesh") mesh_region_present = False if self.mesh_obj.MeshUtility == "cfMesh" and len(self.cf_settings['MeshRegions']) > 0 or \ self.mesh_obj.MeshUtility == "snappyHexMesh" and len(self.snappy_settings['MeshRegions']) > 0: mesh_region_present = True self.settings = { 'Name': self.part_obj.Name, 'MeshPath': self.meshCaseDir, 'FoamRuntime': CfdTools.getFoamRuntime(), 'MeshUtility': self.mesh_obj.MeshUtility, 'MeshRegionPresent': mesh_region_present, 'CfSettings': self.cf_settings, 'SnappySettings': self.snappy_settings, 'GmshSettings': self.gmsh_settings, 'TwoDSettings': self.two_d_settings } if CfdTools.getFoamRuntime() != 'WindowsDocker': self.settings['TranslatedFoamPath'] = CfdTools.translatePath( CfdTools.getFoamDir()) if self.mesh_obj.NumberOfProcesses <= 1: self.mesh_obj.NumberOfProcesses = 1 self.settings['ParallelMesh'] = False else: self.settings['ParallelMesh'] = True self.settings['NumberOfProcesses'] = self.mesh_obj.NumberOfProcesses self.settings['NumberOfThreads'] = self.mesh_obj.NumberOfThreads TemplateBuilder.TemplateBuilder(self.meshCaseDir, self.template_path, self.settings) # Update Allmesh permission - will fail silently on Windows fname = os.path.join(self.meshCaseDir, "Allmesh") import stat s = os.stat(fname) os.chmod(fname, s.st_mode | stat.S_IEXEC) CfdTools.cfdMessage( "Successfully wrote meshCase to folder {}\n".format( self.meshCaseDir))
def write_mesh_case(self): """ Write_case() will collect case setings, and finally build a runnable case. """ tmpdir = tempfile.gettempdir() FreeCAD.Console.PrintMessage( "Populating mesh dictionaries in folder {}\n".format(tmpdir)) _cwd = os.curdir # if not os.path.exists(tmpdir = tempfile.gettempdir()): # raise IOError("Path {} does not exist.".format(tmpdir = tempfile.gettempdir())) os.chdir( tmpdir ) # pyFoam can not write to cwd if FreeCAD is started NOT from terminal if self.mesh_obj.MeshUtility == "cfMesh": self.cf_settings['ClMax'] = self.clmax * self.scale if len(self.cf_settings['BoundaryLayers']) > 0: self.cf_settings['BoundaryLayerPresent'] = True else: self.cf_settings['BoundaryLayerPresent'] = False elif self.mesh_obj.MeshUtility == "snappyHexMesh": bound_box = self.part_obj.Shape.BoundBox bC = 5 # Number of background mesh buffer cells x_min = (bound_box.XMin - bC * self.clmax) * self.scale x_max = (bound_box.XMax + bC * self.clmax) * self.scale y_min = (bound_box.YMin - bC * self.clmax) * self.scale y_max = (bound_box.YMax + bC * self.clmax) * self.scale z_min = (bound_box.ZMin - bC * self.clmax) * self.scale z_max = (bound_box.ZMax + bC * self.clmax) * self.scale cells_x = int(math.ceil(bound_box.XLength / self.clmax) + 2 * bC) cells_y = int(math.ceil(bound_box.YLength / self.clmax) + 2 * bC) cells_z = int(math.ceil(bound_box.ZLength / self.clmax) + 2 * bC) snappy_settings = self.snappy_settings snappy_settings['BlockMesh'] = { "xMin": x_min, "xMax": x_max, "yMin": y_min, "yMax": y_max, "zMin": z_min, "zMax": z_max, "cellsX": cells_x, "cellsY": cells_y, "cellsZ": cells_z } inside_x = self.mesh_obj.PointInMesh.get('x') * self.scale inside_y = self.mesh_obj.PointInMesh.get('y') * self.scale inside_z = self.mesh_obj.PointInMesh.get('z') * self.scale shape_face_names_list = [] for i in self.mesh_obj.ShapeFaceNames: shape_face_names_list.append(i) snappy_settings['ShapeFaceNames'] = tuple(shape_face_names_list) snappy_settings[ 'EdgeRefinementLevel'] = self.mesh_obj.EdgeRefinement snappy_settings['PointInMesh'] = { "x": inside_x, "y": inside_y, "z": inside_z } snappy_settings[ 'CellsBetweenLevels'] = self.mesh_obj.CellsBetweenLevels if self.mesh_obj.NumberCores <= 1: self.mesh_obj.NumberCores = 1 snappy_settings['ParallelMesh'] = False else: snappy_settings['ParallelMesh'] = True snappy_settings['NumberCores'] = self.mesh_obj.NumberCores try: # Make sure we restore cwd after exception here # Perform initialisation here rather than __init__ in case of path changes self.template_path = os.path.join(CfdTools.get_module_path(), "data", "defaultsMesh") mesh_region_present = False if len(self.cf_settings['MeshRegions']) > 0 or len( self.snappy_settings['MeshRegions']) > 0: mesh_region_present = True self.settings = { 'Name': self.part_obj.Name, 'MeshPath': self.meshCaseDir, 'FoamRuntime': CfdTools.getFoamRuntime(), 'TranslatedFoamPath': CfdTools.translatePath(CfdTools.getFoamDir()), 'MeshUtility': self.mesh_obj.MeshUtility, 'MeshRegionPresent': mesh_region_present, 'CfSettings': self.cf_settings, 'SnappySettings': self.snappy_settings } TemplateBuilder.TemplateBuilder(self.meshCaseDir, self.template_path, self.settings) # Update Allmesh permission - will fail silently on Windows fname = os.path.join(self.meshCaseDir, "Allmesh") import stat s = os.stat(fname) os.chmod(fname, s.st_mode | stat.S_IEXEC) except: raise finally: os.chdir(_cwd) # Restore working dir FreeCAD.Console.PrintMessage( "Successfully wrote meshCase to folder {}\n".format(tmpdir))