Ejemplo n.º 1
0
class AdaptiveRefinement(object):
    """
    Class managing the adaptive refinement process, called when executing Multilevel Monte Carlo algorithms.
    This class handles the call to the MeshingApplication, and to other applications, if needed along the process.

    Input:
    - model_coarse: Kratos model class before refinement
    - parameters_coarse: Kratos parameters class before refinement
    - minimal_size_value: minimal size after remeshing
    - maximal_size_value: maximal size after remeshing
    - metric_param: Kratos parameters class containing metric custom settings
    - remesh_param: Kratos parameters class containing remeshing custom settings
    - metric_name: string defining the metring which the class will use to build the metric
    """
    def __init__(self,
                 current_level,
                 model_coarse,
                 parameters_coarse,
                 metric_param,
                 remesh_param,
                 metric_name="hessian"):
        self.model_coarse = model_coarse
        self.parameters_coarse = parameters_coarse
        self.metric_param = metric_param
        self.remesh_param = remesh_param
        self.problem_type = self.parameters_coarse["solver_settings"][
            "solver_type"].GetString()
        self.metric = metric_name
        self.current_level = current_level
        self.wrapper = ParametersWrapper(self.parameters_coarse)

    def ComputeAdaptiveRefinement(self):
        """
        Method computing the refinement of the model based on the solution on the coarse mesh,
        exploiting the hessian metric of the solution.

        Input:
        - self: an instance of the class

        Output:
        - current_model_refined : Kratos model class after refinement
        - current_parameters_refined : Kratos parameters class after refinement
        """
        parameters_coarse = self.parameters_coarse
        model_coarse = self.model_coarse
        metric_param = self.metric_param
        remesh_param = self.remesh_param
        problem_type = self.problem_type
        current_level = self.current_level

        # check MeshingApplication is imported,
        # otherwise raise an error
        if not CheckIfApplicationsAvailable("MeshingApplication"):
            raise Exception(
                "[MultilevelMonteCarloApplication]: MeshingApplication cannot be imported, but it is necessary to perform adaptive refinement."
            )

        if (self.metric is "hessian"):
            # initialize interpolation error
            original_interp_error = metric_param[
                "hessian_strategy_parameters"][
                    "interpolation_error"].GetDouble()
            # set interpolation error for current level
            if current_level > 0:
                coefficient_interp_error = metric_param[
                    "hessian_strategy_parameters"][
                        "coefficient_interpolation_error"].GetDouble()
                metric_param["hessian_strategy_parameters"].RemoveValue(
                    "coefficient_interpolation_error")
                interp_error = original_interp_error * (
                    coefficient_interp_error)**(-current_level)
                # interp_error = original_interp_error/(coefficient_interp_error*current_level)
                metric_param["hessian_strategy_parameters"][
                    "interpolation_error"].SetDouble(interp_error)
            # Setting metric tensor to 0
            domain_size = self.wrapper.GetDomainSize()
            model_part_name = parameters_coarse["solver_settings"][
                "model_part_name"].GetString()
            if domain_size == 2:
                KratosMultiphysics.VariableUtils(
                ).SetNonHistoricalVariableToZero(
                    KratosMultiphysics.MeshingApplication.METRIC_TENSOR_2D,
                    model_coarse.GetModelPart(model_part_name).Nodes)
            elif domain_size == 3:
                KratosMultiphysics.VariableUtils(
                ).SetNonHistoricalVariableToZero(
                    KratosMultiphysics.MeshingApplication.METRIC_TENSOR_3D,
                    model_coarse.GetModelPart(model_part_name).Nodes)
            else:
                err_msg = "Domain size is {}. Supported values are 2 and 3.\n".format(
                    domain_size)
            # calculate NODAL_H
            find_nodal_h = KratosMultiphysics.FindNodalHNonHistoricalProcess(
                model_coarse.GetModelPart(model_part_name))
            find_nodal_h.Execute()

            # build the metric
            if metric_param["hessian_strategy_parameters"].Has(
                    "metric_variable"):
                metric_variables = self.__generate_variable_list_from_input(
                    metric_param["hessian_strategy_parameters"]
                    ["metric_variable"])
                # remove metric value from settings, since we pass it directly in the constructor
                metric_param["hessian_strategy_parameters"].RemoveValue(
                    "metric_variable")
            else:
                raise Exception(
                    "A list of variable is expected under the key [\"hessian_strategy_parameters\"][\"metric_variable\"] of the \"metric\" dictionary."
                )

            for mv in metric_variables:
                local_gradient = KratosMultiphysics.MeshingApplication.ComputeHessianSolMetricProcess(
                    model_coarse.GetModelPart(model_part_name), mv,
                    metric_param)
                local_gradient.Execute()

            # create the remeshing process and execute it
            if KratosMultiphysics.IsDistributedRun():  # MPI
                KratosMultiphysics.mpi.ParallelFillCommunicator(
                    model_coarse.GetModelPart(model_part_name)).Execute()
                if domain_size == 3:
                    if (hasattr(KratosMultiphysics.MeshingApplication,
                                "ParMmgProcess3D")):
                        pmmg_process = KratosMultiphysics.MeshingApplication.ParMmgProcess3D(
                            model_coarse.GetModelPart(model_part_name),
                            remesh_param)
                    else:
                        raise Exception(
                            "[MultilevelMonteCarloApplication]: ParMmgProcess3D atrribute not found within MeshingApplcation. It is required to perform remeshing."
                        )
                else:
                    err_msg = "Domain size is {}. Supported value is 3.\n".format(
                        domain_size)
                    raise Exception(err_msg)
                pmmg_process.Execute()
            else:  # serial
                if domain_size == 2:
                    if (hasattr(KratosMultiphysics.MeshingApplication,
                                "MmgProcess2D")):
                        mmg_process = KratosMultiphysics.MeshingApplication.MmgProcess2D(
                            model_coarse.GetModelPart(model_part_name),
                            remesh_param)
                    else:
                        raise Exception(
                            "[MultilevelMonteCarloApplication]: MmgProcess2D atrribute not found within MeshingApplcation. It is required to perform remeshing."
                        )
                elif domain_size == 3:
                    if (hasattr(KratosMultiphysics.MeshingApplication,
                                "MmgProcess3D")):
                        mmg_process = KratosMultiphysics.MeshingApplication.MmgProcess3D(
                            model_coarse.GetModelPart(model_part_name),
                            remesh_param)
                    else:
                        raise Exception(
                            "[MultilevelMonteCarloApplication]: MmgProcess3D atrribute not found within MeshingApplcation. It is required to perform remeshing."
                        )
                else:
                    err_msg = "Domain size is {}. Supported values are 2 and 3.\n".format(
                        domain_size)
                    raise Exception(err_msg)
                mmg_process.Execute()

            # reset variables if needed
            model_coarse.GetModelPart(model_part_name).ProcessInfo.SetValue(
                KratosMultiphysics.TIME, 0.0)
            model_coarse.GetModelPart(model_part_name).ProcessInfo.SetValue(
                KratosMultiphysics.STEP, 0)
            model_coarse.GetModelPart(model_part_name).ProcessInfo.SetValue(
                KratosMultiphysics.IS_RESTARTED, False)

            if (problem_type
                    in ["monolithic", "FractionalStep", "potential_flow"]):
                model_coarse.GetModelPart(model_part_name).RemoveSubModelPart(
                    "fluid_computational_model_part")

            # the refinement process empties the coarse model part object and fill it with the refined model part
            # the solution on the refined grid is obtained from the interpolation of the coarse solution
            # there are not other operations, therefore to build the new model we just need to take the updated coarse model
            current_model_refined = model_coarse
            current_parameters_refined = parameters_coarse
            return current_model_refined, current_parameters_refined

        else:
            err_msg = "Metric passed to the AdaptiveRefinement class is {}, but the only supported metric is \"hessian\".\n".format(
                self.metric)
            raise Exception(err_msg)

    def ComputeMeshSizeCoarsestLevel(self):
        """
        Method computing the mesh size of coarsest level, estimated as minimum nodal_h.

        Input:
        - self: an instance of the class
        """
        model_coarse = self.model_coarse
        model_part_name = self.wrapper.GetModelPartName()
        # set NODAL_AREA and NODAL_H as non historical variables
        KratosMultiphysics.VariableUtils().SetNonHistoricalVariable(
            KratosMultiphysics.NODAL_AREA, 0.0,
            model_coarse.GetModelPart(model_part_name).Nodes)
        KratosMultiphysics.VariableUtils().SetNonHistoricalVariable(
            KratosMultiphysics.NODAL_H, 0.0,
            model_coarse.GetModelPart(model_part_name).Nodes)
        # calculate NODAL_H
        find_nodal_h = KratosMultiphysics.FindNodalHProcess(
            model_coarse.GetModelPart(model_part_name))
        find_nodal_h = KratosMultiphysics.FindNodalHNonHistoricalProcess(
            model_coarse.GetModelPart(model_part_name))
        find_nodal_h.Execute()
        # compute average mesh size
        mesh_size = 10.0
        for node in model_coarse.GetModelPart(model_part_name).Nodes:
            if (node.GetValue(KratosMultiphysics.NODAL_H) < mesh_size):
                mesh_size = node.GetValue(KratosMultiphysics.NODAL_H)
        self.mesh_size_coarsest_level = mesh_size

    def EstimateMeshSizeCurrentLevel(self):
        """
        Method estimating the mesh size of current level.

        Input:
        - self: an instance of the class
        """
        self.ComputeMeshSizeCoarsestLevel()
        current_level = self.current_level
        if (self.metric is "hessian"):
            original_interp_error = self.metric_param[
                "hessian_strategy_parameters"][
                    "interpolation_error"].GetDouble()
            domain_size = self.wrapper.GetDomainSize()
            if (domain_size == 2):
                coefficient = 2 / 9  # 2d
            elif (domain_size == 3):
                coefficient = 9 / 32  # 3d
            # TODO: compute below interp error level more automatically
            coefficient_interp_error = self.metric_param[
                "hessian_strategy_parameters"][
                    "coefficient_interpolation_error"].GetDouble()
            # interp_error_level = original_interp_error*(coefficient_interp_error)**(-current_level)
            if (current_level > 0):
                interp_error_level = original_interp_error / (
                    coefficient_interp_error * current_level)
            else:  # current_level == 0
                interp_error_level = original_interp_error
            mesh_size_level = self.mesh_size_coarsest_level * sqrt(
                interp_error_level / original_interp_error
            )  # relation from [Alauzet] eqs. pag 34 and 35
            self.mesh_size = mesh_size_level

    def __generate_variable_list_from_input(self, param):
        """
        Method taken and adapted from mmg_progess.py of MeshingApplication.
        Parse a list of variables from input.
        """
        # At least verify that the input is a string
        if not param.IsArray():
            raise Exception("{0} Error: Variable list is unreadable".format(
                self.__class__.__name__))

        # Retrieve variable name from input (a string) and request the corresponding C++ object to the kernel
        variable_list = []
        param_names = param.GetStringArray()
        for variable_name in param_names:
            varriable_type = KratosMultiphysics.KratosGlobals.GetVariableType(
                variable_name)
            if varriable_type == "Double" or varriable_type == "Component":
                variable_list.append(
                    KratosMultiphysics.KratosGlobals.GetVariable(
                        variable_name))
            else:
                variable_list.append(
                    KratosMultiphysics.KratosGlobals.GetVariable(
                        variable_name + "_X"))
                variable_list.append(
                    KratosMultiphysics.KratosGlobals.GetVariable(
                        variable_name + "_Y"))
                if self.wrapper.GetDomainSize() == 3:
                    variable_list.append(
                        KratosMultiphysics.KratosGlobals.GetVariable(
                            variable_name + "_Z"))

        return variable_list
class AdaptiveRefinement(object):
    """
    input:  model_coarse       : Kratos model class before refinement
            parameters_coarse  : Kratos parameters class before refinement
            minimal_size_value : minimal size after remeshing
            maximal_size_value : maximal size after remeshing
            metric_param       : Kratos parameters class containing metric custom settings
            remesh_param       : Kratos parameters class containing remeshing custom settings
    """
    def __init__(self,
                 current_level,
                 model_coarse,
                 parameters_coarse,
                 metric_param,
                 remesh_param,
                 metric_name="hessian"):
        self.model_coarse = model_coarse
        self.parameters_coarse = parameters_coarse
        self.metric_param = metric_param
        self.remesh_param = remesh_param
        self.problem_type = self.parameters_coarse["solver_settings"][
            "solver_type"].GetString()
        self.metric = metric_name
        self.current_level = current_level
        self.wrapper = ParametersWrapper(self.parameters_coarse)

    """
    function computing the refinement of the model based on the solution on the coarse mesh,
    exploiting the hessian metric of the solution
    input:  self: an instance of the class
    output: current_model_refined      : Kratos model class after refinement
            current_parameters_refined : Kratos parameters class after refinement
    """

    def ComputeAdaptiveRefinement(self):
        parameters_coarse = self.parameters_coarse
        model_coarse = self.model_coarse
        metric_param = self.metric_param
        remesh_param = self.remesh_param
        problem_type = self.problem_type
        current_level = self.current_level

        if (self.metric is "hessian"):
            original_interp_error = metric_param[
                "hessian_strategy_parameters"][
                    "interpolation_error"].GetDouble()

            # problem dependent section
            if (problem_type == "potential_flow"):
                model_part_name = parameters_coarse["solver_settings"][
                    "model_part_name"].GetString()
                # set NODAL_AREA and NODAL_H as non historical variables
                KratosMultiphysics.VariableUtils().SetNonHistoricalVariable(
                    KratosMultiphysics.NODAL_AREA, 0.0,
                    model_coarse.GetModelPart(model_part_name).Nodes)
                KratosMultiphysics.VariableUtils().SetNonHistoricalVariable(
                    KratosMultiphysics.NODAL_H, 0.0,
                    model_coarse.GetModelPart(model_part_name).Nodes)
                # Setting Metric Tensor to 0
                KratosMultiphysics.VariableUtils(
                ).SetNonHistoricalVariableToZero(
                    KratosMultiphysics.MeshingApplication.METRIC_TENSOR_2D,
                    model_coarse.GetModelPart(model_part_name).Nodes)
                # calculate NODAL_H
                find_nodal_h = KratosMultiphysics.FindNodalHProcess(
                    model_coarse.GetModelPart(model_part_name))
                find_nodal_h = KratosMultiphysics.FindNodalHNonHistoricalProcess(
                    model_coarse.GetModelPart(model_part_name))
                find_nodal_h.Execute()
                custom_gradient = KratosMultiphysics.CompressiblePotentialFlowApplication.ComputeCustomNodalGradientProcess(
                    model_coarse.GetModelPart(model_part_name),
                    KratosMultiphysics.VELOCITY, KratosMultiphysics.NODAL_AREA)
                custom_gradient.Execute()

                if metric_param.Has("local_gradient_variable"):
                    metric_param.RemoveValue("local_gradient_variable")
                if current_level > 0:
                    coefficient_interp_error = metric_param[
                        "hessian_strategy_parameters"][
                            "coefficient_interpolation_error"].GetDouble()
                    metric_param["hessian_strategy_parameters"].RemoveValue(
                        "coefficient_interpolation_error")
                    # interp_error = original_interp_error*(coefficient_interp_error)**(-current_level)
                    interp_error = original_interp_error / (
                        coefficient_interp_error * current_level)
                    metric_param["hessian_strategy_parameters"][
                        "interpolation_error"].SetDouble(interp_error)

                local_gradient = KratosMeshing.ComputeHessianSolMetricProcess(
                    model_coarse.GetModelPart(model_part_name),
                    KratosMultiphysics.VELOCITY_X, metric_param)
                local_gradient.Execute()
                local_gradient = KratosMeshing.ComputeHessianSolMetricProcess(
                    model_coarse.GetModelPart(model_part_name),
                    KratosMultiphysics.VELOCITY_Y, metric_param)
                local_gradient.Execute()

                # #### OLD APPROACH
                # for node in model_coarse.GetModelPart(model_part_name).Nodes:
                #     vector=node.GetValue(KratosMultiphysics.VELOCITY)
                #     norm=np.linalg.norm(vector)
                #     node.SetSolutionStepValue(KratosMultiphysics.TEMPERATURE,norm)

                # prepare parameters to calculate the gradient of the designed variable
                # local_gradient_variable_string = metric_param["local_gradient_variable"].GetString()
                # local_gradient_variable = KratosMultiphysics.KratosGlobals.GetVariable(metric_param["local_gradient_variable"].GetString())
                # set interpolation error value (level dependent)
                # calculate the gradient of the variable
                # local_gradient = KratosMeshing.ComputeHessianSolMetricProcess(model_coarse.GetModelPart(model_part_name),local_gradient_variable,metric_param)
                # local_gradient.Execute()

                # # add again the removed variable parameter
                # metric_param.AddEmptyValue("local_gradient_variable")
                # metric_param["local_gradient_variable"].SetString(local_gradient_variable_string)

                #### OLD APPROACH

            elif (problem_type == "monolithic"):
                if metric_param.Has("local_gradient_variable"):
                    metric_param.RemoveValue("local_gradient_variable")
                if current_level > 0:
                    coefficient_interp_error = metric_param[
                        "hessian_strategy_parameters"][
                            "coefficient_interpolation_error"].GetDouble()
                    metric_param["hessian_strategy_parameters"].RemoveValue(
                        "coefficient_interpolation_error")
                    # interp_error = original_interp_error*(coefficient_interp_error)**(-current_level)
                    interp_error = original_interp_error / (
                        coefficient_interp_error * current_level)
                    metric_param["hessian_strategy_parameters"][
                        "interpolation_error"].SetDouble(interp_error)
                model_part_name = parameters_coarse["solver_settings"][
                    "model_part_name"].GetString()

                # Setting Metric Tensor to 0
                KratosMultiphysics.VariableUtils(
                ).SetNonHistoricalVariableToZero(
                    KratosMultiphysics.MeshingApplication.METRIC_TENSOR_2D,
                    model_coarse.GetModelPart(model_part_name).Nodes)

                # calculate NODAL_H
                find_nodal_h = KratosMultiphysics.FindNodalHNonHistoricalProcess(
                    model_coarse.GetModelPart(model_part_name))
                find_nodal_h.Execute()
                local_gradient = KratosMeshing.ComputeHessianSolMetricProcess(
                    model_coarse.GetModelPart(model_part_name),
                    KratosFluid.AVERAGE_VELOCITY_X, metric_param)
                local_gradient.Execute()
                local_gradient = KratosMeshing.ComputeHessianSolMetricProcess(
                    model_coarse.GetModelPart(model_part_name),
                    KratosFluid.AVERAGE_VELOCITY_Y, metric_param)
                local_gradient.Execute()

            elif (problem_type == "stationary"):
                if current_level > 0:
                    coefficient_interp_error = metric_param[
                        "hessian_strategy_parameters"][
                            "coefficient_interpolation_error"].GetDouble()
                    metric_param["hessian_strategy_parameters"].RemoveValue(
                        "coefficient_interpolation_error")
                    interp_error = original_interp_error * (
                        coefficient_interp_error)**(-current_level)
                    metric_param["hessian_strategy_parameters"][
                        "interpolation_error"].SetDouble(interp_error)
                model_part_name = parameters_coarse["solver_settings"][
                    "model_part_name"].GetString()
                # Setting Metric Tensor to 0
                KratosMultiphysics.VariableUtils(
                ).SetNonHistoricalVariableToZero(
                    KratosMultiphysics.MeshingApplication.METRIC_TENSOR_2D,
                    model_coarse.GetModelPart(model_part_name).Nodes)
                # calculate NODAL_H
                find_nodal_h = KratosMultiphysics.FindNodalHNonHistoricalProcess(
                    model_coarse.GetModelPart(model_part_name))
                find_nodal_h.Execute()
                local_gradient = KratosMeshing.ComputeHessianSolMetricProcess(
                    model_coarse.GetModelPart(model_part_name),
                    KratosMultiphysics.TEMPERATURE, metric_param)
                local_gradient.Execute()

            # create the remeshing process
            MmgProcess = KratosMeshing.MmgProcess2D(
                model_coarse.GetModelPart(model_part_name), remesh_param)
            MmgProcess.Execute()

            # reset variables if needed
            model_coarse.GetModelPart(model_part_name).ProcessInfo.SetValue(
                KratosMultiphysics.TIME, 0.0)
            model_coarse.GetModelPart(model_part_name).ProcessInfo.SetValue(
                KratosMultiphysics.STEP, 0)
            """
            the refinement process empties the coarse model part object and fill it with the refined model part
            the solution on the refined grid is obtained from the interpolation of the coarse solution
            there are not other operations, therefore to build the new model we just need to take the updated coarse model
            """
            current_model_refined = model_coarse
            current_parameters_refined = parameters_coarse
            return current_model_refined, current_parameters_refined

    """
    method computing the mesh size of coarsest level, estimated as minimum nodal_h
    input:  self : an instance of the class
    """

    def ComputeMeshSizeCoarsestLevel(self):
        model_coarse = self.model_coarse
        parameters_coarse = self.parameters_coarse
        model_part_name = self.wrapper.GetModelPartName()
        # set NODAL_AREA and NODAL_H as non historical variables
        KratosMultiphysics.VariableUtils().SetNonHistoricalVariable(
            KratosMultiphysics.NODAL_AREA, 0.0,
            model_coarse.GetModelPart(model_part_name).Nodes)
        KratosMultiphysics.VariableUtils().SetNonHistoricalVariable(
            KratosMultiphysics.NODAL_H, 0.0,
            model_coarse.GetModelPart(model_part_name).Nodes)
        # calculate NODAL_H
        find_nodal_h = KratosMultiphysics.FindNodalHProcess(
            model_coarse.GetModelPart(model_part_name))
        find_nodal_h = KratosMultiphysics.FindNodalHNonHistoricalProcess(
            model_coarse.GetModelPart(model_part_name))
        find_nodal_h.Execute()
        # compute average mesh size
        mesh_size = 10.0
        for node in model_coarse.GetModelPart(model_part_name).Nodes:
            if (node.GetValue(KratosMultiphysics.NODAL_H) < mesh_size):
                mesh_size = node.GetValue(KratosMultiphysics.NODAL_H)
        self.mesh_size_coarsest_level = mesh_size

    """
    method estimating the mesh size of current level
    input:  self : an instance of the class
    """

    def EstimateMeshSizeCurrentLevel(self):
        self.ComputeMeshSizeCoarsestLevel()
        current_level = self.current_level
        if (self.metric is "hessian"):
            original_interp_error = self.metric_param[
                "hessian_strategy_parameters"][
                    "interpolation_error"].GetDouble()
            domain_size = self.wrapper.GetDomainSize()
            if (domain_size == 2):
                coefficient = 2 / 9  # 2d
            elif (domain_size == 3):
                coefficient = 9 / 32  # 3d
            # TODO: compute below interp error level more automatically
            coefficient_interp_error = self.metric_param[
                "hessian_strategy_parameters"][
                    "coefficient_interpolation_error"].GetDouble()
            # interp_error_level = original_interp_error*(coefficient_interp_error)**(-current_level)
            if (current_level > 0):
                interp_error_level = original_interp_error / (
                    coefficient_interp_error * current_level)
            else:  # current_level == 0
                interp_error_level = original_interp_error
            mesh_size_level = self.mesh_size_coarsest_level * np.sqrt(
                interp_error_level / original_interp_error
            )  # relation from [Alauzet] eqs. pag 34 and 35
            self.mesh_size = mesh_size_level