class StrainEnergyResponseFunction(ResponseFunctionInterface): """Linear strain energy response function. It triggers the primal analysis and uses the primal analysis results to calculate response value and gradient. Attributes ---------- primal_model_part : Model part of the primal analysis object primal_analysis : Primal analysis object of the response function response_function_utility: Cpp utilities object doing the actual computation of response value and gradient. """ def __init__(self, identifier, response_settings, model): self.identifier = identifier with open(response_settings["primal_settings"].GetString() ) as parameters_file: ProjectParametersPrimal = Parameters(parameters_file.read()) self.primal_model_part = _GetModelPart( model, ProjectParametersPrimal["solver_settings"]) self.primal_analysis = StructuralMechanicsAnalysis( model, ProjectParametersPrimal) self.primal_model_part.AddNodalSolutionStepVariable( KratosMultiphysics.SHAPE_SENSITIVITY) self.response_function_utility = StructuralMechanicsApplication.StrainEnergyResponseFunctionUtility( self.primal_model_part, response_settings) def Initialize(self): self.primal_analysis.Initialize() self.response_function_utility.Initialize() def InitializeSolutionStep(self): self.primal_analysis.time = self.primal_analysis._GetSolver( ).AdvanceInTime(self.primal_analysis.time) self.primal_analysis.InitializeSolutionStep() def CalculateValue(self): Logger.PrintInfo("StrainEnergyResponse", "Starting primal analysis for response", self.identifier) startTime = timer.time() self.primal_analysis._GetSolver().Predict() self.primal_analysis._GetSolver().SolveSolutionStep() Logger.PrintInfo("StrainEnergyResponse", "Time needed for solving the primal analysis", round(timer.time() - startTime, 2), "s") startTime = timer.time() value = self.response_function_utility.CalculateValue() self.primal_model_part.ProcessInfo[ StructuralMechanicsApplication.RESPONSE_VALUE] = value Logger.PrintInfo("StrainEnergyResponse", "Time needed for calculating the response value", round(timer.time() - startTime, 2), "s") def CalculateGradient(self): Logger.PrintInfo("StrainEnergyResponse", "Starting gradient calculation for response", self.identifier) startTime = timer.time() self.response_function_utility.CalculateGradient() Logger.PrintInfo("StrainEnergyResponse", "Time needed for calculating gradients", round(timer.time() - startTime, 2), "s") def FinalizeSolutionStep(self): self.primal_analysis.FinalizeSolutionStep() self.primal_analysis.OutputSolutionStep() def Finalize(self): self.primal_analysis.Finalize() def GetValue(self): return self.primal_model_part.ProcessInfo[ StructuralMechanicsApplication.RESPONSE_VALUE] def GetNodalGradient(self, variable): if variable != KratosMultiphysics.SHAPE_SENSITIVITY: raise RuntimeError("GetNodalGradient: No gradient for {}!".format( variable.Name)) gradient = {} for node in self.primal_model_part.Nodes: gradient[node.Id] = node.GetSolutionStepValue(variable) return gradient
class AdjointResponseFunction(ResponseFunctionInterface): """Linear static adjoint strain energy response function. - runs the primal analysis (writes the primal results to an .h5 file) - reads the primal results from the .h5 file into the adjoint model part - uses primal results to calculate value - uses primal results to calculate gradient by running the adjoint analysis Attributes ---------- primal_analysis : Primal analysis object of the response function adjoint_analysis : Adjoint analysis object of the response function """ def __init__(self, identifier, response_settings, model): self.identifier = identifier self.response_settings = response_settings # Create the primal solver with open(self.response_settings["primal_settings"].GetString(), 'r') as parameter_file: primal_parameters = Parameters(parameter_file.read()) self.primal_model_part = _GetModelPart( model, primal_parameters["solver_settings"]) self.primal_analysis = StructuralMechanicsAnalysis( model, primal_parameters) self.primal_data_transfer_with_python = self.response_settings[ "primal_data_transfer_with_python"].GetBool() # Create the adjoint solver adjoint_parameters = self._GetAdjointParameters() adjoint_model = KratosMultiphysics.Model() self.adjoint_model_part = _GetModelPart( adjoint_model, adjoint_parameters["solver_settings"]) # TODO find out why it is not possible to use the same model_part self.adjoint_analysis = StructuralMechanicsAnalysis( adjoint_model, adjoint_parameters) self.primal_state_variables = [KratosMultiphysics.DISPLACEMENT] if primal_parameters["solver_settings"].Has("rotation_dofs"): if primal_parameters["solver_settings"]["rotation_dofs"].GetBool(): self.primal_state_variables.append(KratosMultiphysics.ROTATION) def Initialize(self): self.primal_analysis.Initialize() self.adjoint_analysis.Initialize() def InitializeSolutionStep(self): # Run the primal analysis. # TODO if primal_analysis.status==solved: return Logger.PrintInfo(self._GetLabel(), "Starting primal analysis for response:", self.identifier) startTime = timer.time() if not self.primal_analysis.time < self.primal_analysis.end_time: self.primal_analysis.end_time += 1 self.primal_analysis.RunSolutionLoop() Logger.PrintInfo(self._GetLabel(), "Time needed for solving the primal analysis = ", round(timer.time() - startTime, 2), "s") def CalculateValue(self): startTime = timer.time() value = self._GetResponseFunctionUtility().CalculateValue( self.primal_model_part) Logger.PrintInfo(self._GetLabel(), "Time needed for calculating the response value = ", round(timer.time() - startTime, 2), "s") self.primal_model_part.ProcessInfo[ StructuralMechanicsApplication.RESPONSE_VALUE] = value def CalculateGradient(self): # synchronize the modelparts self._SynchronizeAdjointFromPrimal() startTime = timer.time() Logger.PrintInfo(self._GetLabel(), "Starting adjoint analysis for response:", self.identifier) if not self.adjoint_analysis.time < self.adjoint_analysis.end_time: self.adjoint_analysis.end_time += 1 self.adjoint_analysis.RunSolutionLoop() Logger.PrintInfo(self._GetLabel(), "Time needed for solving the adjoint analysis = ", round(timer.time() - startTime, 2), "s") def GetValue(self): return self.primal_model_part.ProcessInfo[ StructuralMechanicsApplication.RESPONSE_VALUE] def GetNodalGradient(self, variable): if variable != KratosMultiphysics.SHAPE_SENSITIVITY: raise RuntimeError("GetNodalGradient: No gradient for {}!".format( variable.Name)) gradient = {} for node in self.adjoint_model_part.Nodes: gradient[node.Id] = node.GetSolutionStepValue(variable) return gradient def Finalize(self): self.primal_analysis.Finalize() self.adjoint_analysis.Finalize() def _GetResponseFunctionUtility(self): return self.adjoint_analysis._GetSolver().response_function def _SynchronizeAdjointFromPrimal(self): Logger.PrintInfo( self._GetLabel(), "Synchronize primal and adjoint modelpart for response:", self.identifier) if len(self.primal_model_part.Nodes) != len( self.adjoint_model_part.Nodes): raise RuntimeError( "_SynchronizeAdjointFromPrimal: Model parts have a different number of nodes!" ) # TODO this should happen automatically for primal_node, adjoint_node in zip(self.primal_model_part.Nodes, self.adjoint_model_part.Nodes): adjoint_node.X0 = primal_node.X0 adjoint_node.Y0 = primal_node.Y0 adjoint_node.Z0 = primal_node.Z0 adjoint_node.X = primal_node.X adjoint_node.Y = primal_node.Y adjoint_node.Z = primal_node.Z # Put primal solution on adjoint model if self.primal_data_transfer_with_python: Logger.PrintInfo(self._GetLabel(), "Transfer primal state to adjoint model part.") variable_utils = KratosMultiphysics.VariableUtils() for variable in self.primal_state_variables: variable_utils.CopyModelPartNodalVar(variable, self.primal_model_part, self.adjoint_model_part, 0) def _GetAdjointParameters(self): adjoint_settings = self.response_settings[ "adjoint_settings"].GetString() if adjoint_settings == "auto": Logger.PrintInfo( self._GetLabel(), "Automatic set up adjoint parameters for response:", self.identifier) if not self.primal_data_transfer_with_python: raise Exception( "Auto setup of adjoint parameters does only support primal data transfer with python." ) with open(self.response_settings["primal_settings"].GetString(), 'r') as parameter_file: primal_parameters = Parameters(parameter_file.read()) # check that HDF5 process is not there if primal_parameters["processes"].Has("list_other_processes"): for i in range( 0, primal_parameters["processes"] ["list_other_processes"].size()): process = primal_parameters["processes"][ "list_other_processes"][i] raise Exception( "Auto setup of adjoint parameters does not support {} in list_other_processes" .format(process["python_module"].GetString())) # clone primal settings as base for adjoint adjoint_parameters = primal_parameters.Clone() # analysis settings solver_settings = adjoint_parameters["solver_settings"] primal_solver_type = solver_settings["solver_type"].GetString() if primal_solver_type != "static": raise Exception( "Auto setup of adjoint parameters does not support {} solver_type. Only available for 'static'" .format(primal_solver_type)) solver_settings["solver_type"].SetString("adjoint_" + primal_solver_type) if not solver_settings.Has("compute_reactions"): solver_settings.AddEmptyValue("compute_reactions") solver_settings["compute_reactions"].SetBool(False) if not solver_settings.Has("move_mesh_flag"): solver_settings.AddEmptyValue("move_mesh_flag") solver_settings["move_mesh_flag"].SetBool(False) if solver_settings.Has("scheme_settings"): depr_msg = '\nDEPRECATION-WARNING: "scheme_settings" is deprecated, please remove it from your json parameters.\n' Logger.PrintWarning(__name__, depr_msg) solver_settings.RemoveValue("scheme_settings") if solver_settings["model_import_settings"][ "input_type"].GetString() == "use_input_model_part": solver_settings["model_import_settings"][ "input_type"].SetString("mdpa") if solver_settings["model_import_settings"].Has( "input_filename"): file_name = solver_settings["model_import_settings"][ "input_filename"].GetString() else: Logger.PrintWarning( self._GetLabel(), "Automatic adjoint settings creator assumes the model_part_name as input_filename." ) solver_settings["model_import_settings"].AddEmptyValue( "input_filename") file_name = solver_settings["model_part_name"].GetString() solver_settings["model_import_settings"][ "input_filename"].SetString(file_name) # Dirichlet conditions: change variables for i in range( 0, primal_parameters["processes"] ["constraints_process_list"].size()): process = adjoint_parameters["processes"][ "constraints_process_list"][i] variable_name = process["Parameters"][ "variable_name"].GetString() process["Parameters"]["variable_name"].SetString("ADJOINT_" + variable_name) # Neumann conditions - do not modify to read the same load values as in primal: # Output process: # TODO how to add the output process? How find out about the variables? if adjoint_parameters.Has("output_processes"): Logger.PrintInfo( self._GetLabel(), "Output process is removed for adjoint analysis. To enable it define adjoint_parameters yourself." ) adjoint_parameters.RemoveValue("output_processes") # sensitivity settings adjoint_parameters["solver_settings"].AddValue( "sensitivity_settings", self.response_settings["sensitivity_settings"]) # response settings adjoint_parameters["solver_settings"].AddValue( "response_function_settings", self.response_settings) else: # adjoint parameters file is explicitely given - do not change it. with open(self.response_settings["adjoint_settings"].GetString(), 'r') as parameter_file: adjoint_parameters = Parameters(parameter_file.read()) return adjoint_parameters def _GetLabel(self): type_labels = { "adjoint_nodal_displacement": "NodalDisplacement", "adjoint_linear_strain_energy": "StrainEnergy", "adjoint_local_stress": "LocalStress", "adjoint_max_stress": "MaxStress", "adjoint_nodal_reaction": "NodalReaction" } response_type = self.response_settings["response_type"].GetString() return "Adjoint" + type_labels[response_type] + "Response"
class Algorithm(object): def __init__(self): self.model = Kratos.Model() from KratosMultiphysics.DemStructuresCouplingApplication.dem_main_script_ready_for_coupling_with_fem import StructuresCoupledDEMAnalysisStage dem_parameters_file_name = "ProjectParametersDEM.json" with open(dem_parameters_file_name, 'r') as parameter_file: parameters = Kratos.Parameters(parameter_file.read()) self.dem_solution = StructuresCoupledDEMAnalysisStage( self.model, parameters) self.dem_solution.coupling_analysis = weakref.proxy(self) from KratosMultiphysics.StructuralMechanicsApplication.structural_mechanics_analysis import StructuralMechanicsAnalysis structural_parameters_file_name = "ProjectParameters.json" with open(structural_parameters_file_name, 'r') as parameter_file: parameters = Kratos.Parameters(parameter_file.read()) # Create structural solver, main_model_part and added variables self.structural_solution = StructuralMechanicsAnalysis( self.model, parameters) self.AddDEMVariablesToStructural() def AddDEMVariablesToStructural(self): self.structural_solution._GetSolver( ).main_model_part.AddNodalSolutionStepVariable(DemFem.DEM_SURFACE_LOAD) self.structural_solution._GetSolver( ).main_model_part.AddNodalSolutionStepVariable( DemFem.BACKUP_LAST_STRUCTURAL_VELOCITY) self.structural_solution._GetSolver( ).main_model_part.AddNodalSolutionStepVariable( DemFem.BACKUP_LAST_STRUCTURAL_DISPLACEMENT) self.structural_solution._GetSolver( ).main_model_part.AddNodalSolutionStepVariable( DemFem.SMOOTHED_STRUCTURAL_VELOCITY) self.structural_solution._GetSolver( ).main_model_part.AddNodalSolutionStepVariable(Dem.DELTA_DISPLACEMENT) self.structural_solution._GetSolver( ).main_model_part.AddNodalSolutionStepVariable(Dem.DEM_PRESSURE) self.structural_solution._GetSolver( ).main_model_part.AddNodalSolutionStepVariable(Dem.DEM_NODAL_AREA) self.structural_solution._GetSolver( ).main_model_part.AddNodalSolutionStepVariable(Dem.ELASTIC_FORCES) self.structural_solution._GetSolver( ).main_model_part.AddNodalSolutionStepVariable(Dem.CONTACT_FORCES) self.structural_solution._GetSolver( ).main_model_part.AddNodalSolutionStepVariable( Dem.TANGENTIAL_ELASTIC_FORCES) self.structural_solution._GetSolver( ).main_model_part.AddNodalSolutionStepVariable(Dem.SHEAR_STRESS) self.structural_solution._GetSolver( ).main_model_part.AddNodalSolutionStepVariable( Dem.NON_DIMENSIONAL_VOLUME_WEAR) self.structural_solution._GetSolver( ).main_model_part.AddNodalSolutionStepVariable(Dem.IMPACT_WEAR) self.structural_solution._GetSolver( ).main_model_part.AddNodalSolutionStepVariable(DemFem.TARGET_STRESS) self.structural_solution._GetSolver( ).main_model_part.AddNodalSolutionStepVariable(DemFem.REACTION_STRESS) self.structural_solution._GetSolver( ).main_model_part.AddNodalSolutionStepVariable(DemFem.LOADING_VELOCITY) def Run(self): self.Initialize() self.RunSolutionLoop() self.Finalize() def Initialize(self): self.structural_solution.Initialize() # Reading mdpa self.dem_solution.Initialize() # Adding DEM variables and reading self._DetectStructuresSkin() self._TransferStructuresSkinToDem() self.dem_solution._GetSolver().Initialize() mixed_mp = self.model.CreateModelPart('MixedPart') filename = os.path.join( self.dem_solution.post_path, self.dem_solution.DEM_parameters["problem_name"].GetString()) self.gid_output = dem_structures_coupling_gid_output.DemStructuresCouplingGiDOutput( filename, True, "Binary", "Multiples", True, True, self.structural_solution._GetSolver().GetComputingModelPart(), self.dem_solution.spheres_model_part, self.dem_solution.cluster_model_part, self.dem_solution.rigid_face_model_part, self.dem_solution.contact_model_part, mixed_mp) structures_nodal_results = [ "VOLUME_ACCELERATION", "DEM_SURFACE_LOAD", "REACTION", "TARGET_STRESS", "REACTION_STRESS", "LOADING_VELOCITY" ] dem_nodal_results = ["IS_STICKY", "DEM_STRESS_TENSOR"] clusters_nodal_results = [] rigid_faces_nodal_results = [] contact_model_part_results = ["CONTACT_FAILURE"] mixed_nodal_results = ["DISPLACEMENT", "VELOCITY"] gauss_points_results = ["CAUCHY_STRESS_TENSOR"] self.gid_output.initialize_dem_fem_results( structures_nodal_results, dem_nodal_results, clusters_nodal_results, rigid_faces_nodal_results, contact_model_part_results, mixed_nodal_results, gauss_points_results) def _DetectStructuresSkin(self): skin_detection_parameters = Kratos.Parameters(""" { "name_auxiliar_model_part" : "DetectedByProcessSkinModelPart", "name_auxiliar_condition" : "SurfaceLoadFromDEMCondition", "list_model_parts_to_assign_conditions" : [] } """) computing_model_part = self.structural_solution._GetSolver( ).GetComputingModelPart() if (computing_model_part.ProcessInfo[Kratos.DOMAIN_SIZE] == 2): self.structure_skin_detector = Kratos.SkinDetectionProcess2D( computing_model_part, skin_detection_parameters) elif (computing_model_part.ProcessInfo[Kratos.DOMAIN_SIZE] == 3): self.structure_skin_detector = Kratos.SkinDetectionProcess3D( computing_model_part, skin_detection_parameters) else: print( "No dimensions detected for the structures problem. Exiting.") sys.exit() self.structure_skin_detector.Execute() def _TransferStructuresSkinToDem(self): self.structural_mp = self.structural_solution._GetSolver( ).GetComputingModelPart() self.skin_mp = self.structural_mp.GetSubModelPart( "DetectedByProcessSkinModelPart") dem_walls_mp = self.dem_solution.rigid_face_model_part max_prop_id = 0 for prop in dem_walls_mp.Properties: if prop.Id > max_prop_id: max_prop_id = prop.Id props = Kratos.Properties(max_prop_id + 1) # NOTE: this should be more general props[Dem.FRICTION] = -0.5773502691896257 props[Dem.WALL_COHESION] = 0.0 props[Dem.COMPUTE_WEAR] = False props[Dem.SEVERITY_OF_WEAR] = 0.001 props[Dem.IMPACT_WEAR_SEVERITY] = 0.001 props[Dem.BRINELL_HARDNESS] = 200.0 props[Kratos.YOUNG_MODULUS] = 7e9 props[Kratos.POISSON_RATIO] = 0.16 dem_walls_mp.AddProperties(props) DemFem.DemStructuresCouplingUtilities().TransferStructuresSkinToDem( self.skin_mp, dem_walls_mp, props) def RunSolutionLoop(self): self.dem_solution.step = 0 self.dem_solution.time = 0.0 self.dem_solution.time_old_print = 0.0 self.time_dem = 0.0 self.Dt_structural = self.structural_solution._GetSolver( ).settings["time_stepping"]["time_step"].GetDouble() while self.structural_solution.time < self.structural_solution.end_time: portion_of_the_force_which_is_new = 0.4 DemFem.DemStructuresCouplingUtilities().SmoothLoadTrasferredToFem( self.dem_solution.rigid_face_model_part, portion_of_the_force_which_is_new) self.structural_solution.time = self.structural_solution._GetSolver( ).AdvanceInTime(self.structural_solution.time) self.structural_solution.InitializeSolutionStep() self.structural_solution._GetSolver().Predict() self.structural_solution._GetSolver().SolveSolutionStep() self.structural_solution.FinalizeSolutionStep() self.structural_solution.OutputSolutionStep() time_final_DEM_substepping = self.structural_solution.time self.Dt_DEM = self.dem_solution.spheres_model_part.ProcessInfo.GetValue( Kratos.DELTA_TIME) DemFem.InterpolateStructuralSolutionForDEM( ).SaveStructuralSolution(self.structural_mp) DemFem.ComputeDEMFaceLoadUtility().ClearDEMFaceLoads(self.skin_mp) for self.dem_solution.time_dem in self.yield_DEM_time( self.dem_solution.time, time_final_DEM_substepping, self.Dt_DEM): self.dem_solution.time = self.dem_solution.time + self.dem_solution._GetSolver( ).dt self.dem_solution.step += 1 self.dem_solution.DEMFEMProcedures.UpdateTimeInModelParts( self.dem_solution.all_model_parts, self.dem_solution.time, self.dem_solution._GetSolver().dt, self.dem_solution.step) self.dem_solution.InitializeSolutionStep() DemFem.InterpolateStructuralSolutionForDEM( ).InterpolateStructuralSolution( self.structural_mp, self.Dt_structural, self.structural_solution.time, self.dem_solution._GetSolver().dt, self.dem_solution.time) self.dem_solution.SolverSolve() self.dem_solution.FinalizeSolutionStep() DemFem.ComputeDEMFaceLoadUtility().CalculateDEMFaceLoads( self.skin_mp, self.dem_solution._GetSolver().dt, self.Dt_structural) self.dem_solution.DEMFEMProcedures.MoveAllMeshes( self.dem_solution.all_model_parts, self.dem_solution.time, self.dem_solution._GetSolver().dt) #DEMFEMProcedures.MoveAllMeshesUsingATable(rigid_face_model_part, time, dt) #### PRINTING GRAPHS #### os.chdir(self.dem_solution.graphs_path) self.dem_solution.post_utils.ComputeMeanVelocitiesInTrap( "Average_Velocity.txt", self.dem_solution.time, self.dem_solution.graphs_path) self.dem_solution.materialTest.MeasureForcesAndPressure() self.dem_solution.materialTest.PrintGraph( self.dem_solution.time) self.dem_solution.DEMFEMProcedures.PrintGraph( self.dem_solution.time) self.dem_solution.DEMFEMProcedures.PrintBallsGraph( self.dem_solution.time) self.dem_solution.DEMEnergyCalculator.CalculateEnergyAndPlot( self.dem_solution.time) self.dem_solution.BeforePrintingOperations( self.dem_solution.time) #### GiD IO ########################################## if self.dem_solution.IsTimeToPrintPostProcess(): self.dem_solution._GetSolver().PrepareElementsForPrinting() if self.dem_solution.DEM_parameters[ "ContactMeshOption"].GetBool(): self.dem_solution._GetSolver( ).PrepareContactElementsForPrinting() self.dem_solution.PrintResultsForGid( self.dem_solution.time) self.dem_solution.demio.PrintMultifileLists( self.dem_solution.time, self.dem_solution.post_path) self.dem_solution.time_old_print = self.dem_solution.time self.dem_solution.FinalizeTimeStep(self.dem_solution.time) DemFem.InterpolateStructuralSolutionForDEM( ).RestoreStructuralSolution(self.structural_mp) def ReadDemModelParts(self, starting_node_Id=0, starting_elem_Id=0, starting_cond_Id=0): creator_destructor = self.dem_solution.creator_destructor structures_model_part = self.structural_solution._GetSolver( ).GetComputingModelPart() max_node_Id = creator_destructor.FindMaxNodeIdInModelPart( structures_model_part) max_elem_Id = creator_destructor.FindMaxElementIdInModelPart( structures_model_part) max_cond_Id = creator_destructor.FindMaxConditionIdInModelPart( structures_model_part) self.dem_solution.BaseReadModelParts(max_node_Id, max_elem_Id, max_cond_Id) self.dem_solution.all_model_parts.MaxNodeId = max_node_Id def Finalize(self): self.dem_solution.Finalize() self.structural_solution.Finalize() def yield_DEM_time(self, current_time, current_time_plus_increment, delta_time): current_time += delta_time tolerance = 0.0001 while current_time < (current_time_plus_increment - tolerance * delta_time): yield current_time current_time += delta_time current_time = current_time_plus_increment yield current_time