Example #1
0
    def __analyzeShape(self):
        self.communicator.initializeCommunication()
        self.communicator.requestValueOf(self.objectives[0]["identifier"].GetString())
        self.communicator.requestGradientOf(self.objectives[0]["identifier"].GetString())
        self.communicator.requestValueOf(self.constraints[0]["identifier"].GetString())
        self.communicator.requestGradientOf(self.constraints[0]["identifier"].GetString())

        self.analyzer.AnalyzeDesignAndReportToCommunicator(self.design_surface, self.optimization_iteration, self.communicator)

        objGradientDict = self.communicator.getStandardizedGradient(self.objectives[0]["identifier"].GetString())
        conGradientDict = self.communicator.getStandardizedGradient(self.constraints[0]["identifier"].GetString())

        WriteDictionaryDataOnNodalVariable(objGradientDict, self.optimization_model_part, DF1DX)
        WriteDictionaryDataOnNodalVariable(conGradientDict, self.optimization_model_part, DC1DX)

        if self.objectives[0]["project_gradient_on_surface_normals"].GetBool() or self.constraints[0]["project_gradient_on_surface_normals"].GetBool():
            self.model_part_controller.ComputeUnitSurfaceNormals()

        if self.objectives[0]["project_gradient_on_surface_normals"].GetBool():
            self.model_part_controller.ProjectNodalVariableOnUnitSurfaceNormals(DF1DX)

        if self.constraints[0]["project_gradient_on_surface_normals"].GetBool():
            self.model_part_controller.ProjectNodalVariableOnUnitSurfaceNormals(DC1DX)

        self.model_part_controller.DampNodalVariableIfSpecified(DF1DX)
        self.model_part_controller.DampNodalVariableIfSpecified(DC1DX)
Example #2
0
    def __analyzeShape(self):
        self.Communicator.initializeCommunication()
        self.Communicator.requestValueOf(self.only_obj["identifier"].GetString())
        self.Communicator.requestGradientOf(self.only_obj["identifier"].GetString())
        self.Communicator.requestValueOf(self.only_con["identifier"].GetString())
        self.Communicator.requestGradientOf(self.only_con["identifier"].GetString())

        self.Analyzer.AnalyzeDesignAndReportToCommunicator(self.DesignSurface, self.optimizationIteration, self.Communicator)

        objGradientDict = self.Communicator.getStandardizedGradient(self.only_obj["identifier"].GetString())
        conGradientDict = self.Communicator.getStandardizedGradient(self.only_con["identifier"].GetString())

        WriteDictionaryDataOnNodalVariable(objGradientDict, self.OptimizationModelPart, DF1DX)
        WriteDictionaryDataOnNodalVariable(conGradientDict, self.OptimizationModelPart, DC1DX)

        if self.only_obj["project_gradient_on_surface_normals"].GetBool() or self.only_con["project_gradient_on_surface_normals"].GetBool():
            self.GeometryUtilities.ComputeUnitSurfaceNormals()

        if self.only_obj["project_gradient_on_surface_normals"].GetBool():
            self.GeometryUtilities.ProjectNodalVariableOnUnitSurfaceNormals(DF1DX)

        if self.only_con["project_gradient_on_surface_normals"].GetBool():
            self.GeometryUtilities.ProjectNodalVariableOnUnitSurfaceNormals(DC1DX)

        if self.isDampingSpecified:
            self.DampingUtilities.DampNodalVariable(DF1DX)
            self.DampingUtilities.DampNodalVariable(DC1DX)
Example #3
0
    def RunOptimizationLoop(self):
        timer = Timer()
        timer.StartTimer()

        current_lambda = self.lambda0
        penalty_scaling = self.penalty_scaling_0
        penalty_factor = self.penalty_factor_0

        total_iteration = 0
        is_design_converged = False
        is_max_total_iterations_reached = False
        previos_L = None

        for outer_iteration in range(1, self.max_outer_iterations + 1):
            for inner_iteration in range(1, self.max_inner_iterations + 1):

                total_iteration += 1
                timer.StartNewLap()

                print(
                    "\n>======================================================================================="
                )
                print("> ", timer.GetTimeStamp(), ": Starting iteration ",
                      outer_iteration, ".", inner_iteration, ".",
                      total_iteration, "(outer . inner . total)")
                print(
                    ">=======================================================================================\n"
                )

                # Initialize new shape
                self.model_part_controller.UpdateTimeStep(total_iteration)

                for node in self.design_surface.Nodes:
                    new_shape_change = node.GetSolutionStepValue(
                        ALPHA_MAPPED) * node.GetValue(
                            BEAD_DIRECTION) * self.bead_height
                    node.SetSolutionStepValue(SHAPE_CHANGE, new_shape_change)

                self.model_part_controller.DampNodalVariableIfSpecified(
                    SHAPE_CHANGE)

                for node in self.design_surface.Nodes:
                    shape_update = node.GetSolutionStepValue(
                        SHAPE_CHANGE, 0) - node.GetSolutionStepValue(
                            SHAPE_CHANGE, 1)
                    node.SetSolutionStepValue(SHAPE_UPDATE, shape_update)

                self.model_part_controller.UpdateMeshAccordingInputVariable(
                    SHAPE_UPDATE)
                self.model_part_controller.SetReferenceMeshToMesh()

                # Analyze shape
                self.communicator.initializeCommunication()
                self.communicator.requestValueOf(
                    self.objectives[0]["identifier"].GetString())
                self.communicator.requestGradientOf(
                    self.objectives[0]["identifier"].GetString())

                self.analyzer.AnalyzeDesignAndReportToCommunicator(
                    self.design_surface, total_iteration, self.communicator)

                objective_value = self.communicator.getStandardizedValue(
                    self.objectives[0]["identifier"].GetString())
                objGradientDict = self.communicator.getStandardizedGradient(
                    self.objectives[0]["identifier"].GetString())
                WriteDictionaryDataOnNodalVariable(
                    objGradientDict, self.optimization_model_part, DF1DX)

                self.model_part_controller.DampNodalVariableIfSpecified(DF1DX)

                # Compute sensitivities w.r.t. scalar design variable alpha
                for node in self.design_surface.Nodes:
                    raw_gradient = node.GetSolutionStepValue(DF1DX)
                    bead_dir = node.GetValue(BEAD_DIRECTION)

                    dF1dalpha_i = self.bead_height * (
                        raw_gradient[0] * bead_dir[0] + raw_gradient[1] *
                        bead_dir[1] + raw_gradient[2] * bead_dir[2])
                    node.SetSolutionStepValue(DF1DALPHA, dF1dalpha_i)

                # Map gradient of objective
                self.mapper.InverseMap(DF1DALPHA, DF1DALPHA_MAPPED)

                # Compute scaling
                max_norm_objective_gradient = self.optimization_utilities.ComputeMaxNormOfNodalVariable(
                    DF1DALPHA_MAPPED)

                if outer_iteration == 1 and inner_iteration == min(
                        3, self.max_inner_iterations):
                    if self.bead_side == "positive" or self.bead_side == "negative":
                        max_norm_penalty_gradient = 1.0
                    elif self.bead_side == "both":
                        max_norm_penalty_gradient = 2.0

                    penalty_scaling = max_norm_objective_gradient / max_norm_penalty_gradient

                # Compute penalization term
                penalty_value = 0.0
                if self.bead_side == "positive":
                    for node in self.design_surface.Nodes:
                        if not node.Is(BOUNDARY):
                            alpha_i = node.GetSolutionStepValue(ALPHA)
                            penalty_value += penalty_scaling * (alpha_i -
                                                                alpha_i**2)

                            penalty_gradient_i = penalty_scaling * (
                                1 - 2 * alpha_i)
                            node.SetSolutionStepValue(DPDALPHA,
                                                      penalty_gradient_i)

                elif self.bead_side == "negative":
                    for node in self.design_surface.Nodes:
                        if not node.Is(BOUNDARY):
                            alpha_i = node.GetSolutionStepValue(ALPHA)
                            penalty_value += penalty_scaling * (-alpha_i -
                                                                alpha_i**2)

                            penalty_gradient_i = penalty_scaling * (
                                -1 - 2 * alpha_i)
                            node.SetSolutionStepValue(DPDALPHA,
                                                      penalty_gradient_i)

                elif self.bead_side == "both":
                    for node in self.design_surface.Nodes:
                        if not node.Is(BOUNDARY):
                            alpha_i = node.GetSolutionStepValue(ALPHA)
                            penalty_value += penalty_scaling * (-alpha_i**2 +
                                                                1)

                            penalty_gradient_i = penalty_scaling * (-2 *
                                                                    alpha_i)
                            node.SetSolutionStepValue(DPDALPHA,
                                                      penalty_gradient_i)

                # Filter penalty term if specified
                if self.filter_penalty_term:
                    self.mapper.InverseMap(DPDALPHA, DPDALPHA_MAPPED)

                # Compute value of Lagrange function
                L = objective_value + current_lambda * penalty_value + 0.5 * penalty_factor * penalty_value**2
                if inner_iteration == 1:
                    dL_relative = 0.0
                else:
                    dL_relative = 100 * (L / previos_L - 1)

                # Compute gradient of Lagrange function
                if self.filter_penalty_term:
                    penalty_gradient_variable = DPDALPHA_MAPPED
                else:
                    penalty_gradient_variable = DPDALPHA
                for node in self.design_surface.Nodes:
                    dLdalpha_i = node.GetSolutionStepValue(
                        DF1DALPHA_MAPPED
                    ) + current_lambda * node.GetSolutionStepValue(
                        penalty_gradient_variable)
                    node.SetSolutionStepValue(DLDALPHA, dLdalpha_i)

                # Normalization using infinity norm
                dLdalpha_for_normalization = {}
                for node in self.design_surface.Nodes:
                    nodal_alpha = node.GetSolutionStepValue(ALPHA)
                    if nodal_alpha == self.lower_bound or nodal_alpha == self.upper_bound or node.Is(
                            BOUNDARY):
                        dLdalpha_for_normalization[node.Id] = 0.0
                    else:
                        dLdalpha_for_normalization[
                            node.Id] = node.GetSolutionStepValue(DLDALPHA)**2

                max_value = math.sqrt(max(dLdalpha_for_normalization.values()))
                if max_value == 0.0:
                    max_value = 1.0

                # Compute updated design variable
                for node in self.design_surface.Nodes:
                    dalpha = -self.step_size * node.GetSolutionStepValue(
                        DLDALPHA) / max_value
                    alpha_new = node.GetSolutionStepValue(ALPHA) + dalpha

                    # Enforce bounds
                    alpha_new = max(alpha_new, self.lower_bound)
                    alpha_new = min(alpha_new, self.upper_bound)

                    # Enforce constraints
                    if node.Is(BOUNDARY):
                        alpha_new = 0.0

                    node.SetSolutionStepValue(ALPHA, alpha_new)

                    alpha_new_vectorized = alpha_new * node.GetValue(
                        BEAD_DIRECTION)
                    node.SetSolutionStepValue(CONTROL_POINT_CHANGE,
                                              alpha_new_vectorized)

                # Map design variables
                self.mapper.Map(ALPHA, ALPHA_MAPPED)

                # Log current optimization step and store values for next iteration
                additional_values_to_log = {}
                additional_values_to_log[
                    "step_size"] = self.algorithm_settings["line_search"][
                        "step_size"].GetDouble()
                additional_values_to_log["outer_iteration"] = outer_iteration
                additional_values_to_log["inner_iteration"] = inner_iteration
                additional_values_to_log["lagrange_value"] = L
                additional_values_to_log[
                    "lagrange_value_relative_change"] = dL_relative
                additional_values_to_log["penalty_value"] = penalty_value
                additional_values_to_log["penalty_lambda"] = current_lambda
                additional_values_to_log["penalty_scaling"] = penalty_scaling
                additional_values_to_log["penalty_factor"] = penalty_factor
                additional_values_to_log[
                    "max_norm_objective_gradient"] = max_norm_objective_gradient

                self.data_logger.LogCurrentValues(total_iteration,
                                                  additional_values_to_log)
                self.data_logger.LogCurrentDesign(total_iteration)

                previos_L = L

                # Convergence check of inner loop
                if total_iteration == self.max_total_iterations:
                    is_max_total_iterations_reached = True
                    break

                if inner_iteration >= self.min_inner_iterations and inner_iteration > 1:
                    # In the first outer iteration, the constraint is not yet active and properly scaled. Therefore, the objective is used to check the relative improvement
                    if outer_iteration == 1:
                        if abs(
                                self.data_logger.GetValue(
                                    "rel_change_obj", total_iteration)
                        ) < self.inner_iteration_tolerance:
                            break
                    else:
                        if abs(dL_relative) < self.inner_iteration_tolerance:
                            break

                if penalty_value == 0.0:
                    is_design_converged = True
                    break

                print("\n> Time needed for current optimization step = ",
                      timer.GetLapTime(), "s")
                print("> Time needed for total optimization so far = ",
                      timer.GetTotalTime(), "s")

            # Compute penalty factor such that estimated Lagrange multiplier is obtained
            if outer_iteration == 1:
                penalty_factor = self.estimated_lagrange_multiplier / penalty_value

            # Update lambda
            current_lambda = current_lambda + penalty_factor * penalty_value

            print("\n> Time needed for current optimization step = ",
                  timer.GetLapTime(), "s")
            print("> Time needed for total optimization so far = ",
                  timer.GetTotalTime(), "s")

            # Check convergence of outer loop
            if outer_iteration == self.max_outer_iterations:
                print(
                    "\n> Maximal outer iterations of optimization problem reached!"
                )
                break

            if is_max_total_iterations_reached:
                print(
                    "\n> Maximal total iterations of optimization problem reached!"
                )
                break

            if is_design_converged:
                print(
                    "\n> Update of design variables is zero. Optimization converged!"
                )
                break
    def __PostProcessGradientsObtainedFromAnalysis(self):
        # Compute surface normals if required
        if self.objectives[0]["project_gradient_on_surface_normals"].GetBool():
            self.geometry_utilities.ComputeUnitSurfaceNormals()
        else:
            for itr in range(self.constraints.size()):
                if self.constraints[itr][
                        "project_gradient_on_surface_normals"]:
                    self.geometry_utilities.ComputeUnitSurfaceNormals()

        # Process objective gradients
        obj = self.objectives[0]
        obj_id = obj["identifier"].GetString()

        obj_gradients_dict = self.communicator.getStandardizedGradient(obj_id)

        nodal_variable = KratosGlobals.GetVariable("DF1DX")
        WriteDictionaryDataOnNodalVariable(obj_gradients_dict,
                                           self.optimization_model_part,
                                           nodal_variable)

        # Projection on surface normals
        if obj["project_gradient_on_surface_normals"].GetBool():
            self.geometry_utilities.ProjectNodalVariableOnUnitSurfaceNormals(
                nodal_variable)

        # Damping
        if self.is_damping_specified:
            self.damping_utilities.DampNodalVariable(nodal_variable)

        # Mapping
        nodal_variable_mapped = KratosGlobals.GetVariable("DF1DX_MAPPED")
        self.mapper.MapToDesignSpace(nodal_variable, nodal_variable_mapped)
        self.mapper.MapToGeometrySpace(nodal_variable_mapped,
                                       nodal_variable_mapped)

        # Damping
        if self.is_damping_specified:
            self.damping_utilities.DampNodalVariable(nodal_variable_mapped)

        # Process constraint gradients
        for itr in range(self.constraints.size()):
            con = self.constraints[itr]
            con_id = con["identifier"].GetString()

            eq_gradients_dict = self.communicator.getStandardizedGradient(
                con_id)

            nodal_variable = KratosGlobals.GetVariable("DC" + str(itr + 1) +
                                                       "DX")
            WriteDictionaryDataOnNodalVariable(eq_gradients_dict,
                                               self.optimization_model_part,
                                               nodal_variable)

            # Projection on surface normals
            if con["project_gradient_on_surface_normals"].GetBool():
                self.geometry_utilities.ProjectNodalVariableOnUnitSurfaceNormals(
                    nodal_variable)

            # Damping
            if self.is_damping_specified:
                self.damping_utilities.DampNodalVariable(nodal_variable)

            # Mapping
            nodal_variable_mapped = KratosGlobals.GetVariable("DC" +
                                                              str(itr + 1) +
                                                              "DX_MAPPED")
            self.mapper.MapToDesignSpace(nodal_variable, nodal_variable_mapped)
            self.mapper.MapToGeometrySpace(nodal_variable_mapped,
                                           nodal_variable_mapped)

            # Damping
            if self.is_damping_specified:
                self.damping_utilities.DampNodalVariable(nodal_variable_mapped)