Esempio n. 1
0
    def __init__(self, analysis_obj):
        self.case_folder = None
        self.mesh_file_name = None
        self.template_path = None

        self.analysis_obj = analysis_obj
        self.solver_obj = CfdTools.getSolver(analysis_obj)
        self.physics_model = CfdTools.getPhysicsModel(analysis_obj)
        self.mesh_obj = CfdTools.getMesh(analysis_obj)
        self.material_objs = CfdTools.getMaterials(analysis_obj)
        self.bc_group = CfdTools.getCfdBoundaryGroup(analysis_obj)
        self.initial_conditions = CfdTools.getInitialConditions(analysis_obj)
        self.reporting_functions = CfdTools.getReportingFunctionsGroup(
            analysis_obj)
        self.scalar_transport_objs = CfdTools.getScalarTransportFunctionsGroup(
            analysis_obj)
        self.porous_zone_objs = CfdTools.getPorousZoneObjects(analysis_obj)
        self.initialisation_zone_objs = CfdTools.getInitialisationZoneObjects(
            analysis_obj)
        self.zone_objs = CfdTools.getZoneObjects(analysis_obj)
        self.dynamic_mesh_refinement_obj = CfdTools.getDynamicMeshAdaptation(
            analysis_obj)
        self.mesh_generated = False
        self.working_dir = CfdTools.getOutputPath(self.analysis_obj)
        self.progressCallback = None

        self.settings = None
Esempio n. 2
0
    def __init__(self, cart_mesh_obj):
        self.mesh_obj = cart_mesh_obj
        self.analysis = CfdTools.getParentAnalysisObject(self.mesh_obj)

        self.part_obj = self.mesh_obj.Part  # Part to mesh
        self.scale = 0.001  # Scale mm to m

        # Default to 2 % of bounding box characteristic length
        self.clmax = Units.Quantity(
            self.mesh_obj.CharacteristicLengthMax).Value
        if self.clmax <= 0.0:
            shape = self.part_obj.Shape
            cl_bound_mag = math.sqrt(shape.BoundBox.XLength**2 +
                                     shape.BoundBox.YLength**2 +
                                     shape.BoundBox.ZLength**2)
            cl_bound_min = min(
                min(shape.BoundBox.XLength, shape.BoundBox.YLength),
                shape.BoundBox.ZLength)
            self.clmax = min(
                0.02 * cl_bound_mag,
                0.4 * cl_bound_min)  # Always in internal format, i.e. mm

        # Only used by gmsh - what purpose?
        self.clmin = 0.0

        self.dimension = self.mesh_obj.ElementDimension

        self.cf_settings = {}
        self.snappy_settings = {}
        self.gmsh_settings = {}
        self.extrusion_settings = {}

        self.error = False

        output_path = CfdTools.getOutputPath(self.analysis)
        self.getFilePaths(output_path)

        # 2D array of list of faces (index into shape) in each patch, indexed by [bc_id+1][meshregion_id+1]
        self.patch_faces = []
        # 2D array of names of each patch, indexed by [bc_id+1][meshregion_id+1]
        self.patch_names = []

        self.progressCallback = None
Esempio n. 3
0
    def __init__(self, solver_runner_obj):
        ui_path = os.path.join(CfdTools.getModulePath(), 'Gui',
                               "TaskPanelCfdSolverControl.ui")
        self.form = FreeCADGui.PySideUic.loadUi(ui_path)

        self.analysis_object = CfdTools.getActiveAnalysis()

        self.solver_runner = solver_runner_obj
        self.solver_object = solver_runner_obj.solver

        # update UI
        self.console_message = ''

        self.solver_object.Proxy.solver_process = CfdConsoleProcess(
            finished_hook=self.solverFinished,
            stdout_hook=self.gotOutputLines,
            stderr_hook=self.gotErrorLines)
        self.Timer = QtCore.QTimer()
        self.Timer.setInterval(1000)
        self.Timer.timeout.connect(self.updateText)

        self.form.terminateSolver.clicked.connect(self.killSolverProcess)
        self.form.terminateSolver.setEnabled(False)

        self.open_paraview = QtCore.QProcess()

        self.working_dir = CfdTools.getOutputPath(self.analysis_object)

        self.updateUI()

        # Connect Signals and Slots
        self.form.pb_write_inp.clicked.connect(self.write_input_file_handler)
        self.form.pb_edit_inp.clicked.connect(self.editSolverInputFile)
        self.form.pb_run_solver.clicked.connect(self.runSolverProcess)
        self.form.pb_paraview.clicked.connect(self.openParaview)

        self.Start = time.time()
        self.Timer.start()
Esempio n. 4
0
    def test_new_analysis(self):
        fccPrint('--------------- Start of CFD tests ---------------')
        fccPrint('Checking CFD {} analysis ...'.format(self.__class__.__doc_name))
        self.createNewAnalysis()
        self.assertTrue(self.analysis, "CfdTest of analysis failed")

        fccPrint('Checking CFD {} physics object ...'.format(self.__class__.__doc_name))
        self.createNewPhysics()
        self.assertTrue(self.physics_object, "CfdTest of physics object failed")
        self.analysis.addObject(self.physics_object)

        fccPrint('Checking CFD {} initialise ...'.format(self.__class__.__doc_name))
        self.createNewInitialise()
        self.assertTrue(self.initialise_object, "CfdTest of initialise failed")
        self.analysis.addObject(self.initialise_object)

        fccPrint('Checking CFD {} fluid property ...'.format(self.__class__.__doc_name))
        self.createNewFluidProperty()
        self.assertTrue(self.material_object, "CfdTest of fluid property failed")
        self.analysis.addObject(self.material_object)

        fccPrint('Checking Cfd {} velocity inlet boundary ...'.format(self.__class__.__doc_name))
        self.createInletBoundary()
        self.assertTrue(self.inlet_boundary, "CfdTest of inlet boundary failed")
        self.analysis.addObject(self.inlet_boundary)

        fccPrint('Checking Cfd {} velocity outlet boundary ...'.format(self.__class__.__doc_name))
        self.createOutletBoundary()
        self.assertTrue(self.outlet_boundary, "CfdTest of outlet boundary failed")
        self.analysis.addObject(self.outlet_boundary)

        fccPrint('Checking Cfd {} wall boundary ...'.format(self.__class__.__doc_name))
        self.createWallBoundary()
        self.assertTrue(self.wall_boundary, "CfdTest of wall boundary failed")
        self.analysis.addObject(self.wall_boundary)

        fccPrint('Checking Cfd {} slip boundary ...'.format(self.__class__.__doc_name))
        self.createSlipBoundary()
        self.assertTrue(self.slip_boundary, "CfdTest of slip boundary failed")
        self.analysis.addObject(self.slip_boundary)

        fccPrint('Checking CFD {} mesh ...'.format(self.__class__.__doc_name))
        self.createNewMesh('mesh')
        self.assertTrue(self.mesh_object, "CfdTest of mesh failed")
        self.analysis.addObject(self.mesh_object)

        fccPrint('Checking CFD {} solver ...'.format(self.__class__.__doc_name))
        self.createNewSolver()
        self.assertTrue(self.solver_object, self.__class__.__doc_name + " of solver failed")
        self.analysis.addObject(self.solver_object)

        fccPrint('Writing {} case files ...'.format(self.__class__.__doc_name))
        self.analysis.OutputPath = temp_dir
        self.solver_object.InputCaseName = "case" + self.__class__.__doc_name
        self.mesh_object.CaseName = "meshCase" + self.__class__.__doc_name
        self.writeCaseFiles()

        mesh_ref_dir = os.path.join(test_file_dir, "cases", self.__class__.__doc_name, "meshCase")
        mesh_case_dir = os.path.join(CfdTools.getOutputPath(self.analysis), self.mesh_object.CaseName)
        ref_dir = os.path.join(test_file_dir, "cases", self.__class__.__doc_name, "case")
        case_dir = os.path.join(CfdTools.getOutputPath(self.analysis), self.solver_object.InputCaseName)

        comparePaths(mesh_ref_dir, mesh_case_dir, self)
        comparePaths(ref_dir, case_dir, self)

        #shutil.rmtree(mesh_case_dir)
        #shutil.rmtree(case_dir)

        fccPrint('--------------- End of CFD tests ---------------')
Esempio n. 5
0
    def runSolverProcess(self):
        self.Start = time.time()

        # Check for changes that require remesh
        if FreeCAD.GuiUp and (self.analysis_object.NeedsMeshRewrite
                              or self.analysis_object.NeedsCaseRewrite
                              or self.analysis_object.NeedsMeshRerun):

            if self.analysis_object.NeedsCaseRewrite:
                if self.analysis_object.NeedsMeshRewrite or self.analysis_object.NeedsMeshRerun:
                    text = "The case may need to be re-meshed and the case setup re-written based on changes " + \
                           "you have made to the model.\n\nRe-mesh and re-write case setup first?"
                else:
                    text = "The case setup may need to be re-written based on changes " + \
                           "you have made to the model.\n\nRe-write case setup first?"
            else:
                if self.analysis_object.NeedsMeshRewrite or self.analysis_object.NeedsMeshRerun:
                    text = "The case may need to be re-meshed based on changes " + \
                           "you have made to the model.\n\nRe-mesh case first?"

            if QtGui.QMessageBox.question(None,
                                          "CfdOF Workbench",
                                          text,
                                          defaultButton=QtGui.QMessageBox.Yes
                                          ) == QtGui.QMessageBox.Yes:
                self.Start = time.time()

                if self.analysis_object.NeedsMeshRewrite or self.analysis_object.NeedsMeshRerun:
                    from CfdOF.Mesh import CfdMeshTools
                    mesh_obj = CfdTools.getMeshObject(self.analysis_object)
                    cart_mesh = CfdMeshTools.CfdMeshTools(mesh_obj)
                    cart_mesh.progressCallback = self.consoleMessage
                    if self.analysis_object.NeedsMeshRewrite:
                        #Write mesh
                        cart_mesh.writeMesh()
                        self.analysis_object.NeedsMeshRewrite = False
                        self.analysis_object.NeedsMeshRerun = True

                if self.analysis_object.NeedsCaseRewrite:
                    self.write_input_file_handler()

                if self.analysis_object.NeedsMeshRerun:
                    # Run mesher
                    self.solver_object.Proxy.solver_process = CfdConsoleProcess(
                        finished_hook=self.mesherFinished,
                        stdout_hook=self.gotOutputLines,
                        stderr_hook=self.gotErrorLines)

                    cart_mesh.error = False
                    cmd = CfdTools.makeRunCommand('./Allmesh',
                                                  cart_mesh.meshCaseDir,
                                                  source_env=False)
                    FreeCAD.Console.PrintMessage('Executing: ' +
                                                 ' '.join(cmd) + '\\n')
                    env_vars = CfdTools.getRunEnvironment()
                    self.solver_object.Proxy.solver_process.start(
                        cmd, env_vars=env_vars)
                    if self.solver_object.Proxy.solver_process.waitForStarted(
                    ):
                        # Setting solve button to inactive to ensure that two instances of the same simulation aren't started
                        # simultaneously
                        self.form.pb_write_inp.setEnabled(False)
                        self.form.pb_run_solver.setEnabled(False)
                        self.form.terminateSolver.setEnabled(True)
                        self.consoleMessage("Mesher started ...")
                        return
            else:
                self.Start = time.time()

        QApplication.setOverrideCursor(Qt.WaitCursor)
        FreeCADGui.doCommand("from CfdOF import CfdTools")
        FreeCADGui.doCommand("from CfdOF import CfdConsoleProcess")
        self.solver_object.Proxy.solver_runner = self.solver_runner
        FreeCADGui.doCommand("proxy = FreeCAD.ActiveDocument." +
                             self.solver_object.Name + ".Proxy")
        # This is a workaround to emit code into macro without actually running it
        FreeCADGui.doCommand("proxy.running_from_macro = True")
        self.solver_object.Proxy.running_from_macro = False
        FreeCADGui.doCommand(
            "if proxy.running_from_macro:\n" +
            "  analysis_object = FreeCAD.ActiveDocument." +
            self.analysis_object.Name + "\n" +
            "  solver_object = FreeCAD.ActiveDocument." +
            self.solver_object.Name + "\n" +
            "  working_dir = CfdTools.getOutputPath(analysis_object)\n" +
            "  case_name = solver_object.InputCaseName\n" +
            "  solver_directory = os.path.abspath(os.path.join(working_dir, case_name))\n"
            + "  import CfdRunnableFoam\n" +
            "  solver_runner = CfdRunnableFoam.CfdRunnableFoam(analysis_object, solver_object)\n"
            + "  cmd = solver_runner.get_solver_cmd(solver_directory)\n" +
            "  FreeCAD.Console.PrintMessage(' '.join(cmd) + '\\n')\n" +
            "  env_vars = solver_runner.getRunEnvironment()\n" +
            "  solver_process = CfdConsoleProcess.CfdConsoleProcess(stdout_hook=solver_runner.process_output)\n"
            + "  solver_process.start(cmd, env_vars=env_vars)\n" +
            "  solver_process.waitForFinished()\n")
        working_dir = CfdTools.getOutputPath(self.analysis_object)
        case_name = self.solver_object.InputCaseName
        solver_directory = os.path.abspath(os.path.join(
            working_dir, case_name))
        cmd = self.solver_runner.get_solver_cmd(solver_directory)
        FreeCAD.Console.PrintMessage(' '.join(cmd) + '\\n')
        env_vars = self.solver_runner.getRunEnvironment()
        self.solver_object.Proxy.solver_process = CfdConsoleProcess(
            finished_hook=self.solverFinished,
            stdout_hook=self.gotOutputLines,
            stderr_hook=self.gotErrorLines)
        self.solver_object.Proxy.solver_process.start(cmd, env_vars=env_vars)
        if self.solver_object.Proxy.solver_process.waitForStarted():
            # Setting solve button to inactive to ensure that two instances of the same simulation aren't started
            # simultaneously
            self.form.pb_write_inp.setEnabled(False)
            self.form.pb_run_solver.setEnabled(False)
            self.form.terminateSolver.setEnabled(True)
            self.form.pb_paraview.setEnabled(True)
            self.consoleMessage("Solver started")
        else:
            self.consoleMessage("Error starting solver")
        QApplication.restoreOverrideCursor()
Esempio n. 6
0
    def process_output(self, text):
        log_lines = text.split('\n')
        prev_niter = self.niter
        for line in log_lines:
            line = line.rstrip()
            split = line.split()

            # Only record the first residual per outer iteration
            if line.startswith(u"Time = "):
                try:
                    time_val = float(line.lstrip(u"Time = "))
                except ValueError:
                    pass
                else:
                    self.prev_time = self.latest_time
                    self.latest_time = time_val
                    self.prev_num_outer_iters = self.latest_outer_iter
                    if self.latest_time > 0:
                        # Don't keep spurious time zero
                        self.latest_outer_iter = 0
                        self.niter += 1
                    self.in_forces_section = None
                    self.in_forcecoeffs_section = None

            if line.find(u"PIMPLE: iteration ") >= 0 or line.find(
                    u"pseudoTime: iteration ") >= 0:
                self.latest_outer_iter += 1
                # Don't increment counter on first outer iter as this was already done with time
                if self.latest_outer_iter > 1:
                    self.niter += 1

            if line.startswith(u"forces") and (line.endswith(u"write:")
                                               or line.endswith(u"execute:")):
                self.in_forces_section = split[1]
            if line.startswith(u"forceCoeffs") and (
                    line.endswith(u"write:") or line.endswith(u"execute:")):
                self.in_forcecoeffs_section = split[1]
            if not line.strip():
                # Blank line
                self.in_forces_section = None
                self.in_forcecoeffs_section = None

            # Add a point to the time axis for each outer iteration
            if self.niter > len(self.time):
                self.time.append(self.latest_time)
                if self.latest_outer_iter > 0:
                    # Outer-iteration case
                    # Create virtual times to space the residuals of the outer iterations nicely on the time graph
                    self.prev_num_outer_iters = max(self.prev_num_outer_iters,
                                                    self.latest_outer_iter)
                    for i in range(self.latest_outer_iter):
                        self.time[-(
                            self.latest_outer_iter - i)] = self.prev_time + (
                                self.latest_time - self.prev_time) * (
                                    (i + 1) / self.prev_num_outer_iters)

            if "Ux," in split and self.niter > len(self.UxResiduals):
                self.UxResiduals.append(float(split[7].split(',')[0]))
            if "Uy," in split and self.niter > len(self.UyResiduals):
                self.UyResiduals.append(float(split[7].split(',')[0]))
            if "Uz," in split and self.niter > len(self.UzResiduals):
                self.UzResiduals.append(float(split[7].split(',')[0]))
            if "p," in split and self.niter > len(self.pResiduals):
                self.pResiduals.append(float(split[7].split(',')[0]))
            if "p_rgh," in split and self.niter > len(self.pResiduals):
                self.pResiduals.append(float(split[7].split(',')[0]))
            if "h," in split and self.niter > len(self.EResiduals):
                self.EResiduals.append(float(split[7].split(',')[0]))
            # HiSA coupled residuals
            if "Residual:" in split and self.niter > len(self.rhoResiduals):
                self.rhoResiduals.append(float(split[4]))
                self.UxResiduals.append(float(split[5].lstrip('(')))
                self.UyResiduals.append(float(split[6]))
                self.UzResiduals.append(float(split[7].rstrip(')')))
                self.EResiduals.append(float(split[8]))
            if "k," in split and self.niter > len(self.kResiduals):
                self.kResiduals.append(float(split[7].split(',')[0]))
            if "epsilon," in split and self.niter > len(self.epsilonResiduals):
                self.epsilonResiduals.append(float(split[7].split(',')[0]))
            if "omega," in split and self.niter > len(self.omegaResiduals):
                self.omegaResiduals.append(float(split[7].split(',')[0]))
            if "nuTilda," in split and self.niter > len(self.nuTildaResiduals):
                self.nuTildaResiduals.append(float(split[7].split(',')[0]))
            if "gammaInt," in split and self.niter > len(
                    self.gammaIntResiduals):
                self.gammaIntResiduals.append(float(split[7].split(',')[0]))
            if "ReThetat," in split and self.niter > len(
                    self.ReThetatResiduals):
                self.ReThetatResiduals.append(float(split[7].split(',')[0]))

            # Force monitors
            if self.in_forces_section:
                f = self.forces[self.in_forces_section]
                if (("Pressure" in split) or
                    ("pressure"
                     in split)) and self.niter - 1 > len(f['pressureXForces']):
                    f['pressureXForces'].append(float(split[2].lstrip("(")))
                    f['pressureYForces'].append(float(split[3]))
                    f['pressureZForces'].append(float(split[4].rstrip(")")))
                if (("Viscous" in split) or
                    ("viscous"
                     in split)) and self.niter - 1 > len(f['viscousXForces']):
                    f['viscousXForces'].append(float(split[2].lstrip("(")))
                    f['viscousYForces'].append(float(split[3]))
                    f['viscousZForces'].append(float(split[4].rstrip(")")))

            # Force coefficient monitors
            if self.in_forcecoeffs_section:
                fc = self.force_coeffs[self.in_forcecoeffs_section]
                if "Cd" in split and self.niter - 1 > len(fc['cdCoeffs']):
                    fc['cdCoeffs'].append(float(split[2]))
                if "Cl" in split and self.niter - 1 > len(fc['clCoeffs']):
                    fc['clCoeffs'].append(float(split[2]))

        # Update plots
        if self.niter > 1 and self.niter > prev_niter:
            self.solver.Proxy.residual_plotter.updateValues(
                self.time,
                OrderedDict([('$\\rho$', self.rhoResiduals),
                             ('$U_x$', self.UxResiduals),
                             ('$U_y$', self.UyResiduals),
                             ('$U_z$', self.UzResiduals),
                             ('$p$', self.pResiduals),
                             ('$E$', self.EResiduals),
                             ('$k$', self.kResiduals),
                             ('$\\epsilon$', self.epsilonResiduals),
                             ('$\\tilde{\\nu}$', self.nuTildaResiduals),
                             ('$\\omega$', self.omegaResiduals),
                             ('$\\gamma$', self.gammaIntResiduals),
                             ('$Re_{\\theta}$', self.ReThetatResiduals)]))

            for fn in self.forces:
                f = self.forces[fn]
                self.solver.Proxy.forces_plotters[fn].updateValues(
                    self.time,
                    OrderedDict([('$Pressure_x$', f['pressureXForces']),
                                 ('$Pressure_y$', f['pressureYForces']),
                                 ('$Pressure_z$', f['pressureZForces']),
                                 ('$Viscous_x$', f['viscousXForces']),
                                 ('$Viscous_y$', f['viscousYForces']),
                                 ('$Viscous_z$', f['viscousZForces'])]))

            for fcn in self.force_coeffs:
                fc = self.force_coeffs[fcn]
                self.solver.Proxy.force_coeffs_plotters[fcn].updateValues(
                    self.time,
                    OrderedDict([('$C_D$', fc['cdCoeffs']),
                                 ('$C_L$', fc['clCoeffs'])]))

        # Probes
        for pn in self.probes:
            p = self.probes[pn]
            if p['file'] is None:
                working_dir = CfdTools.getOutputPath(self.analysis)
                case_name = self.solver.InputCaseName
                solver_dir = os.path.abspath(
                    os.path.join(working_dir, case_name))
                try:
                    f = open(
                        os.path.join(solver_dir, 'postProcessing', pn, '0',
                                     p['field']))
                    p['file'] = f
                except OSError:
                    pass
            if p['file']:
                ntimes = len(p['time'])
                is_vector = False

                for l in p['file'].readlines():
                    l = l.strip()
                    if len(l) and not l.startswith('#'):
                        s = l.split()
                        p['time'].append(float(s[0]))

                        if s[1].startswith('('):
                            is_vector = True
                        while len(p['values']) < len(s) - 1:
                            p['values'].append([])
                        for i in range(1, len(s)):
                            s[i] = s[i].lstrip('(').rstrip(')')
                            p['values'][i - 1].append(float(s[i]))

                if len(p['time']) > ntimes:
                    legends = []
                    for pi in p['points']:
                        points_str = '({}, {}, {}) m'.format(
                            *(Units.Quantity(pij, Units.Length).getValueAs('m')
                              for pij in (pi.x, pi.y, pi.z)))
                        if is_vector:
                            legends.append('{}$_x$ @ '.format(p['field']) +
                                           points_str)
                            legends.append('{}$_y$ @ '.format(p['field']) +
                                           points_str)
                            legends.append('{}$_z$ @ '.format(p['field']) +
                                           points_str)
                        else:
                            legends.append('${}$ @ '.format(p['field']) +
                                           points_str)
                    self.solver.Proxy.probes_plotters[pn].updateValues(
                        p['time'], OrderedDict(zip(legends, p['values'])))