def __init__(self, fluid_model_part, structure_model_part, combined_model_part, compute_reactions, box_corner1, box_corner2, domain_size, add_nodes): self.domain_size = domain_size self.compute_reactions = compute_reactions self.echo_level = 0 # saving the different model parts self.combined_model_part = combined_model_part # contains both structure and fluid self.fluid_model_part = fluid_model_part # contains only fluid elements self.structure_model_part = structure_model_part # contains only structural elements # adaptivity options self.add_nodes = bool(add_nodes) print("Add nodes? ", self.add_nodes) # time integration scheme damp_factor = -0.3 self.time_scheme = ResidualBasedPredictorCorrectorBossakScheme( damp_factor) # definition of the solvers # self.model_linear_solver = SkylineLUFactorizationSolver() pDiagPrecond = DiagonalPreconditioner() self.model_linear_solver = BICGSTABSolver(1e-9, 5000, pDiagPrecond) # definition of the convergence criteria self.conv_criteria = DisplacementCriteria(1e-6, 1e-9) self.pressure_calculate_process = PressureCalculateProcess( fluid_model_part, domain_size) self.ulf_apply_bc_process = UlfApplyBCProcess(fluid_model_part) self.ulf_time_step_dec_process = UlfTimeStepDecProcess( fluid_model_part) self.mark_fluid_process = MarkFluidProcess(fluid_model_part) self.mark_close_nodes_process = MarkCloseNodesProcess(fluid_model_part) self.mark_outer_nodes_process = MarkOuterNodesProcess(fluid_model_part) self.node_erase_process = NodeEraseProcess(fluid_model_part) # tools to save and merge the structural contributions self.save_structure_model_part_process = SaveStructureModelPartProcess( ) self.save_structure_conditions_process = SaveStructureConditionsProcess( ) self.merge_model_parts_process = MergeModelPartsProcess() # temporary ... i need it to calculate the nodal area self.UlfUtils = UlfUtils() self.PfemUtils = PfemUtils() # self.save_structural_elements self.alpha_shape = 1.5 self.h_multiplier = 0.1 # saving the limits of the box (all the nodes external to this will be erased) self.box_corner1 = box_corner1 self.box_corner2 = box_corner2 if (domain_size == 2): self.Mesher = TriGenPFEMModeler() self.combined_neigh_finder = FindNodalNeighboursProcess( combined_model_part, 9, 18) self.fluid_neigh_finder = FindNodalNeighboursProcess( fluid_model_part, 9, 18) # this is needed if we want to also store the conditions a node belongs to self.condition_neigh_finder = FindConditionsNeighboursProcess( fluid_model_part, 2, 10) elif (domain_size == 3): # self.Mesher = TetGenModeler() # improved mesher self.Mesher = TetGenPfemModeler() self.combined_neigh_finder = FindNodalNeighboursProcess( combined_model_part, 20, 30) self.fluid_neigh_finder = FindNodalNeighboursProcess( fluid_model_part, 20, 30) # this is needed if we want to also store the conditions a node belongs to self.condition_neigh_finder = FindConditionsNeighboursProcess( fluid_model_part, 3, 20) print("after reading all the model contains:") print(self.fluid_model_part) # detect initial size distribution - note that initially the fluid model part contains # all the elements of both structure and fluid ... this is only true after reading the input (self.fluid_neigh_finder).Execute() Hfinder = FindNodalHProcess(fluid_model_part) Hfinder.Execute()
class ULF_FSISolver: def __init__(self, fluid_model_part, structure_model_part, combined_model_part, compute_reactions, box_corner1, box_corner2, domain_size, add_nodes): self.domain_size = domain_size self.compute_reactions = compute_reactions self.echo_level = 0 # saving the different model parts self.combined_model_part = combined_model_part # contains both structure and fluid self.fluid_model_part = fluid_model_part # contains only fluid elements self.structure_model_part = structure_model_part # contains only structural elements # adaptivity options self.add_nodes = bool(add_nodes) print("Add nodes? ", self.add_nodes) # time integration scheme damp_factor = -0.3 self.time_scheme = ResidualBasedPredictorCorrectorBossakScheme( damp_factor) # definition of the solvers # self.model_linear_solver = SkylineLUFactorizationSolver() pDiagPrecond = DiagonalPreconditioner() self.model_linear_solver = BICGSTABSolver(1e-9, 5000, pDiagPrecond) # definition of the convergence criteria self.conv_criteria = DisplacementCriteria(1e-6, 1e-9) self.pressure_calculate_process = PressureCalculateProcess( fluid_model_part, domain_size) self.ulf_apply_bc_process = UlfApplyBCProcess(fluid_model_part) self.ulf_time_step_dec_process = UlfTimeStepDecProcess( fluid_model_part) self.mark_fluid_process = MarkFluidProcess(fluid_model_part) self.mark_close_nodes_process = MarkCloseNodesProcess(fluid_model_part) self.mark_outer_nodes_process = MarkOuterNodesProcess(fluid_model_part) self.node_erase_process = NodeEraseProcess(fluid_model_part) # tools to save and merge the structural contributions self.save_structure_model_part_process = SaveStructureModelPartProcess( ) self.save_structure_conditions_process = SaveStructureConditionsProcess( ) self.merge_model_parts_process = MergeModelPartsProcess() # temporary ... i need it to calculate the nodal area self.UlfUtils = UlfUtils() self.PfemUtils = PfemUtils() # self.save_structural_elements self.alpha_shape = 1.5 self.h_multiplier = 0.1 # saving the limits of the box (all the nodes external to this will be erased) self.box_corner1 = box_corner1 self.box_corner2 = box_corner2 if (domain_size == 2): self.Mesher = TriGenPFEMModeler() self.combined_neigh_finder = FindNodalNeighboursProcess( combined_model_part, 9, 18) self.fluid_neigh_finder = FindNodalNeighboursProcess( fluid_model_part, 9, 18) # this is needed if we want to also store the conditions a node belongs to self.condition_neigh_finder = FindConditionsNeighboursProcess( fluid_model_part, 2, 10) elif (domain_size == 3): # self.Mesher = TetGenModeler() # improved mesher self.Mesher = TetGenPfemModeler() self.combined_neigh_finder = FindNodalNeighboursProcess( combined_model_part, 20, 30) self.fluid_neigh_finder = FindNodalNeighboursProcess( fluid_model_part, 20, 30) # this is needed if we want to also store the conditions a node belongs to self.condition_neigh_finder = FindConditionsNeighboursProcess( fluid_model_part, 3, 20) print("after reading all the model contains:") print(self.fluid_model_part) # detect initial size distribution - note that initially the fluid model part contains # all the elements of both structure and fluid ... this is only true after reading the input (self.fluid_neigh_finder).Execute() Hfinder = FindNodalHProcess(fluid_model_part) Hfinder.Execute() # # delta time estimation based on the non-negativity of the jacobian def EstimateDeltaTime(self, max_dt, domain_size): # return (self.UlfUtils).EstimateDeltaTime(min_dt,max_dt,self.combined_model_part) return (self.ulf_time_step_dec_process).EstimateDeltaTime( max_dt, domain_size) # def Initialize(self): # creating the solution strategy CalculateReactionFlag = bool(self.compute_reactions) ReformDofSetAtEachStep = True MoveMeshFlag = True import ulf_strategy_python self.solver = ulf_strategy_python.ULFStrategyPython( self.combined_model_part, self.time_scheme, self.model_linear_solver, self.conv_criteria, CalculateReactionFlag, ReformDofSetAtEachStep, MoveMeshFlag, self.domain_size) print("self.echo_level = ", self.echo_level) (self.solver).SetEchoLevel(self.echo_level) print("finished initialization of the fluid strategy") # saving the structural elements (self.mark_fluid_process).Execute() # we need this before saving the structrural elements print("Saving STRUCTURE") (self.save_structure_model_part_process).SaveStructure( self.fluid_model_part, self.structure_model_part) (self.save_structure_conditions_process).SaveStructureConditions( self.fluid_model_part, self.structure_model_part) # marking the fluid (self.fluid_neigh_finder).Execute() (self.ulf_apply_bc_process).Execute() (self.mark_fluid_process).Execute() # remeshing before the first solution for node in self.fluid_model_part.Nodes: node.SetSolutionStepValue(IS_FREE_SURFACE, 0, 0.0) self.Remesh() # def CheckForInvertedElements(self): # volume = (self.UlfUtils).CalculateVolume(self.combined_model_part,self.domain_size) volume = (self.UlfUtils).CalculateVolume(self.fluid_model_part, self.domain_size) inverted_elements = False if (volume < 0.0): volume = -volume inverted_elements = True return [inverted_elements, volume] # def Solve(self, lagrangian_inlet_process): print("solving the fluid problem") inverted_elements = (self.solver).Solve(self.domain_size, self.UlfUtils) print("successful solution of the fluid ") self.lagrangian_inlet_process = lagrangian_inlet_process reduction_factor = 0.5 max_reduction_steps = 5 time_reduction_step = 0 while (inverted_elements and time_reduction_step <= max_reduction_steps): print(" *************************************************** ") print("inverted element found ... reducing the time step") (self.UlfUtils).ReduceTimeStep(self.combined_model_part, reduction_factor) (self.UlfUtils).ReduceTimeStep(self.fluid_model_part, reduction_factor) (self.UlfUtils).ReduceTimeStep(self.structure_model_part, reduction_factor) print("reduction_step = ", time_reduction_step) time_reduction_step = time_reduction_step + 1 # copying vars from the old step # for node in (self.combined_model_part).Nodes: # pold = node.GetSolutionStepValue(PRESSURE,1); # dispold = node.GetSolutionStepValue(DISPLACEMENT,1); # velold = node.GetSolutionStepValue(VELOCITY,1); # accold = node.GetSolutionStepValue(ACCELERATION,1); # # node.SetSolutionStepValue(PRESSURE,0,pold); # node.SetSolutionStepValue(DISPLACEMENT,0,dispold); # node.SetSolutionStepValue(VELOCITY,0,velold); # node.SetSolutionStepValue(ACCELERATION,0,accold); self.solver.MoveMesh() print("time step reduction completed") print(" *************************************************** ") (self.solver).Solve(self.domain_size, self.UlfUtils) [inverted_elements, vol] = self.CheckForInvertedElements() if (inverted_elements): print( "***********************************************************************" ) print( "***********************************************************************" ) print( "CRITICAL: ... element is still inverted after reducing the time step" ) print( "***********************************************************************" ) print( "***********************************************************************" ) factor = 2.0**5 # this is the original time step (self.UlfUtils).ReduceTimeStep(self.combined_model_part, factor) (self.UlfUtils).ReduceTimeStep(self.fluid_model_part, factor) (self.UlfUtils).ReduceTimeStep(self.structure_model_part, factor) # for node in (self.combined_model_part).Nodes: # pold = node.GetSolutionStepValue(PRESSURE,1); # dispold = node.GetSolutionStepValue(DISPLACEMENT,1); # velold = node.GetSolutionStepValue(VELOCITY,1); # accold = node.GetSolutionStepValue(ACCELERATION,1); # # node.SetSolutionStepValue(PRESSURE,0,pold); # node.SetSolutionStepValue(DISPLACEMENT,0,dispold); # node.SetSolutionStepValue(VELOCITY,0,velold); # node.SetSolutionStepValue(ACCELERATION,0,accold); self.solver.MoveMesh() print("advancing in time without doing anything...") (self.solver).PredictionStep(self.domain_size, self.UlfUtils) # print "pressure contribution process" - to be executed using exclusively fluid elements # and neighbouring relationships self.lagrangian_inlet_process.Execute() (self.fluid_neigh_finder).Execute() (self.UlfUtils).CalculateNodalArea(self.fluid_model_part, self.domain_size) (self.pressure_calculate_process).Execute() # self.lagrangian_inlet_process.Execute() # print "remeshing" self.Remesh() # # def Remesh(self): # self.PfemUtils.MarkNodesTouchingWall(self.fluid_model_part, self.domain_size, 0.15) self.PfemUtils.MarkNodesTouchingWall(self.fluid_model_part, self.domain_size, 0.05) # erase all conditions and elements prior to remeshing ((self.combined_model_part).Elements).clear() ((self.combined_model_part).Conditions).clear() ((self.combined_model_part).Nodes).clear() ((self.fluid_model_part).Elements).clear() ((self.fluid_model_part).Conditions).clear() # self.UlfUtils.DeleteFreeSurfaceNodesBladder(self.fluid_model_part) # marking nodes outside of the bounding box self.UlfUtils.MarkLonelyNodesForErasing(self.fluid_model_part) (self.mark_outer_nodes_process).MarkOuterNodes(self.box_corner1, self.box_corner2) self.node_erase_process.Execute() h_factor = 0.1 # remesh CHECK for 3D or 2D if (self.domain_size == 2): #(self.Mesher).ReGenerateMesh("UpdatedLagrangianFluid2Dinc", self.fluid_model_part, self.node_erase_process, self.add_nodes, self.alpha_shape) (self.Mesher).ReGenerateMesh("UpdatedLagrangianFluid2D", "Condition2D", self.fluid_model_part, self.node_erase_process, True, self.add_nodes, self.alpha_shape, h_factor) elif (self.domain_size == 3): (self.Mesher).ReGenerateMesh("UpdatedLagrangianFluid3D", "Condition3D", self.fluid_model_part, self.node_erase_process, True, self.add_nodes, self.alpha_shape, h_factor) # calculating fluid neighbours before applying boundary conditions (self.fluid_neigh_finder).Execute() (self.condition_neigh_finder).Execute() # print "marking fluid" and applying fluid boundary conditions (self.ulf_apply_bc_process).Execute() (self.mark_fluid_process).Execute() # merging the structural elements back (they are saved in the Initialize) (self.merge_model_parts_process).MergeParts(self.fluid_model_part, self.structure_model_part, self.combined_model_part) # calculating the neighbours for the overall model (self.combined_neigh_finder).Execute() # self.UlfUtils.MarkLonelyNodesForErasing(self.fluid_model_part, self.domain_size) # self.node_erase_process.Execute() print("end of remesh fucntion") # def FindNeighbours(self): (self.neigh_finder).Execute()
def __init__(self, out_file, fluid_only_model_part, fluid_model_part, structure_model_part, combined_model_part, FSI, compute_reactions, box_corner1, box_corner2, domain_size, add_nodes, bulk_modulus, density): self.out_file = out_file self.compute_reactions = compute_reactions self.domain_size = domain_size; self.echo_level = 0 self.counter = int(0) # TO REMESH OR NOT: 0 - no remeshing, 1 - remeshing self.add_nodes = bool(add_nodes) self.FSI = bool(FSI) # K - the bulk modulus self.bulk_modulus = bulk_modulus self.density = density # saving the different model parts self.combined_model_part = combined_model_part; # contains both structure and fluid self.fluid_model_part = fluid_model_part; # contains only fluid elements, but all nodes! self.structure_model_part = structure_model_part; # contains only structural elements self.fluid_only_model_part = fluid_only_model_part; # contains only fluid elements and nodes # time integration scheme (dam_factor= alpha_bossak) self.damp_factor = -0.3 self.time_scheme = ResidualBasedPredictorCorrectorBossakScheme(self.damp_factor) # definition of the solvers self.pres_time_scheme = ResidualBasedIncrementalUpdateStaticScheme() self.pres_linear_solver = CGSolver(1e-3, 1000) # SkylineLUFactorizationSolver() # definition of the convergence criteria self.conv_criteria = DisplacementCriteria(1e-6,1e-9) #self.conv_criteria = IncrementalDisplacementCriteria(1e-3, 1e-6) # self.pressure_calculate_process = PressureCalculateProcess(fluid_model_part,domain_size); self.ulf_apply_bc_process = UlfApplyBCProcess(fluid_model_part); self.ulf_time_step_dec_process = UlfTimeStepDecProcess(fluid_model_part); self.mark_fluid_process = MarkFluidProcess(fluid_model_part); self.mark_close_nodes_process = MarkCloseNodesProcess(fluid_model_part); self.mark_outer_nodes_process = MarkOuterNodesProcess(fluid_model_part); self.node_erase_process = NodeEraseProcess(fluid_model_part); # tools to save and merge the structural contributions self.save_structure_model_part_process = SaveStructureModelPartProcess(); self.save_structure_conditions_process = SaveStructureConditionsProcess(); self.merge_model_parts_process = MergeModelPartsProcess(); # this will save fluid only model part self.save_fluid_only_process = SaveFluidOnlyProcess(); # temporary ... i need it to calculate the nodal area self.UlfUtils = UlfUtils() self.PfemUtils = PfemUtils() # self.save_structural_elements self.alpha_shape = 1.5; self.h_multiplier = 0.1 # saving the limits of the box (all the nodes external to this will be erased) self.box_corner1 = box_corner1 self.box_corner2 = box_corner2 if(domain_size == 2): # self.Mesher = TriGenModeler() self.Mesher = TriGenPFEMModeler() self.combined_neigh_finder = FindNodalNeighboursProcess(combined_model_part, 9, 18) self.fluid_neigh_finder = FindNodalNeighboursProcess(fluid_model_part, 9, 18) self.fluid_only_neigh_finder = FindNodalNeighboursProcess(fluid_only_model_part, 9, 18) # this is needed if we want to also store the conditions a node belongs to self.condition_neigh_finder = FindConditionsNeighboursProcess(fluid_model_part, 2, 10) elif (domain_size == 3): # improved mesher self.Mesher = TetGenPfemModeler() # self.Mesher = TetGenModeler() self.combined_neigh_finder = FindNodalNeighboursProcess(combined_model_part, 20, 30) self.fluid_neigh_finder = FindNodalNeighboursProcess(fluid_model_part, 20, 30) self.fluid_only_neigh_finder = FindNodalNeighboursProcess(fluid_only_model_part, 20, 30) # this is needed if we want to also store the conditions a node belongs to self.condition_neigh_finder = FindConditionsNeighboursProcess(fluid_model_part, 3, 20) print("after reading all the model contains:") print(self.fluid_model_part) # detect initial size distribution - note that initially the fluid model part contains # all the elements of both structure and fluid ... this is only true after reading the input (self.fluid_neigh_finder).Execute(); self.Hfinder = FindNodalHProcess(fluid_model_part); self.Hfinder.Execute(); self.ResetNodalHAtLonelyNodes() #assigning average nodal h to lonely nodes self.AssignHtoLonelyStructureNodes()
class ULF_FSISolver: def __init__(self, out_file, fluid_model_part, structure_model_part, combined_model_part, compute_reactions, box_corner1, box_corner2, domain_size, add_nodes, bulk_modulus, density): self.out_file = out_file self.compute_reactions = compute_reactions self.domain_size = domain_size self.echo_level = 0 self.counter = int(0) # TO REMESH OR NOT: 0 - no remeshing, 1 - remeshing self.add_nodes = bool(add_nodes) # K - the bulk modulus self.bulk_modulus = bulk_modulus self.density = density # saving the different model parts self.combined_model_part = combined_model_part # contains both structure and fluid self.fluid_model_part = fluid_model_part # contains only fluid elements self.structure_model_part = structure_model_part # contains only structural elements # time integration scheme damp_factor = -0.3 self.time_scheme = ResidualBasedPredictorCorrectorBossakScheme( damp_factor) # definition of the solvers # self.model_linear_solver = SkylineLUFactorizationSolver() pDiagPrecond = DiagonalPreconditioner() self.model_linear_solver = BICGSTABSolver(1e-8, 5000, pDiagPrecond) # definition of the convergence criteria self.conv_criteria = DisplacementCriteria(1e-6, 1e-9) # self.pressure_calculate_process = PressureCalculateProcess(fluid_model_part,domain_size); self.ulf_apply_bc_process = UlfApplyBCProcess(fluid_model_part) self.ulf_time_step_dec_process = UlfTimeStepDecProcess( fluid_model_part) self.mark_fluid_process = MarkFluidProcess(fluid_model_part) self.mark_close_nodes_process = MarkCloseNodesProcess(fluid_model_part) self.mark_outer_nodes_process = MarkOuterNodesProcess(fluid_model_part) self.node_erase_process = NodeEraseProcess(fluid_model_part) # tools to save and merge the structural contributions self.save_structure_model_part_process = SaveStructureModelPartProcess( ) self.save_structure_conditions_process = SaveStructureConditionsProcess( ) self.merge_model_parts_process = MergeModelPartsProcess() # temporary ... i need it to calculate the nodal area self.UlfUtils = UlfUtils() self.PfemUtils = PfemUtils() # self.save_structural_elements self.alpha_shape = 1.5 self.h_multiplier = 0.3 # saving the limits of the box (all the nodes external to this will be erased) self.box_corner1 = box_corner1 self.box_corner2 = box_corner2 if (domain_size == 2): # self.Mesher = TriGenModeler() self.Mesher = TriGenPFEMModeler() self.combined_neigh_finder = FindNodalNeighboursProcess( combined_model_part, 9, 18) self.fluid_neigh_finder = FindNodalNeighboursProcess( fluid_model_part, 9, 18) # this is needed if we want to also store the conditions a node belongs to self.condition_neigh_finder = FindConditionsNeighboursProcess( fluid_model_part, 2, 10) elif (domain_size == 3): # improved mesher self.Mesher = TetGenPfemModeler() # self.Mesher = TetGenModeler() self.combined_neigh_finder = FindNodalNeighboursProcess( combined_model_part, 20, 30) self.fluid_neigh_finder = FindNodalNeighboursProcess( fluid_model_part, 20, 30) # this is needed if we want to also store the conditions a node belongs to self.condition_neigh_finder = FindConditionsNeighboursProcess( fluid_model_part, 3, 20) print("after reading all the model contains:") print(self.fluid_model_part) # detect initial size distribution - note that initially the fluid model part contains # all the elements of both structure and fluid ... this is only true after reading the input (self.fluid_neigh_finder).Execute() Hfinder = FindNodalHProcess(fluid_model_part) Hfinder.Execute() # # delta time estimation based on the non-negativity of the jacobian def EstimateDeltaTime(self, max_dt, domain_size): # return (self.UlfUtils).EstimateDeltaTime(min_dt,max_dt,self.combined_model_part) return (self.ulf_time_step_dec_process).EstimateDeltaTime( max_dt, domain_size) # # this function is needed only in case there is a lagrangian nodes-inlet in the problem # three numbers - are veolicties in x y and z directions # def MoveInletNodes(self, model_part): # (self.UlfUtils).MoveInletNodes(self.fluid_model_part, 0.1, 0.0, 0.0) # def Initialize(self): # creating the solution strategy CalculateReactionFlag = bool(self.compute_reactions) ReformDofSetAtEachStep = True MoveMeshFlag = True import ulf_strategy_python_inc self.solver = ulf_strategy_python_inc.ULFStrategyPythonInc( self.out_file, self.combined_model_part, self.fluid_model_part, self.time_scheme, self.model_linear_solver, self.conv_criteria, CalculateReactionFlag, ReformDofSetAtEachStep, MoveMeshFlag, self.domain_size, self.bulk_modulus, self.density) print("self.echo_level = ", self.echo_level) (self.solver).SetEchoLevel(self.echo_level) print("finished initialization of the fluid strategy") # saving the structural elements (self.mark_fluid_process).Execute() # we need this before saving the structrural elements # we specify domain size, to deal with problems involving membarnes in 3D in a specific way (see save_structure_model_part_process.h (self.save_structure_model_part_process).SaveStructure( self.fluid_model_part, self.structure_model_part) (self.save_structure_conditions_process).SaveStructureConditions( self.fluid_model_part, self.structure_model_part) # creating initially empty container for lagrangian inlet-nodes # lagrangian_inlet_model_part = ModelPart("LagrangianInletPart"); # self.lagrangian_inlet_model_part = lagrangian_inlet_model_part; # saving the lagrangian inlet-nodes if they exist #(self.UlfUtils).SaveLagrangianInlet(self.fluid_model_part, self.lagrangian_inlet_model_part) # marking the fluid (self.fluid_neigh_finder).Execute() (self.combined_neigh_finder).Execute() (self.ulf_apply_bc_process).Execute() (self.mark_fluid_process).Execute() # caluclating nodal area in order to calculate pressures (self.UlfUtils).CalculateNodalArea(self.fluid_model_part, self.domain_size) # remeshing before the first solution self.Remesh() # def CheckForInvertedElements(self): volume = (self.UlfUtils).CalculateVolume(self.combined_model_part, self.domain_size) inverted_elements = False if (volume < 0.0): volume = -volume inverted_elements = True return [inverted_elements, volume] # def Solve(self, lagrangian_inlet_process): # next lines serve only in case of lagrangian inlet # for node in self.fluid_model_part.Nodes: # if (node.GetSolutionStepValue(IS_LAGRANGIAN_INLET)!=1 and (node.GetSolutionStepValue(IS_STRUCTURE)!=1)): # node.Free(DISPLACEMENT_X) # node.Free(DISPLACEMENT_Y) # node.Free(DISPLACEMENT_Z) print("solving the fluid problem") inverted_elements = (self.solver).Solve(self.domain_size, self.UlfUtils) print("successful solution of the fluid ") self.lagrangian_inlet_process = lagrangian_inlet_process reduction_factor = 0.5 max_reduction_steps = 0 time_reduction_step = 0 while (inverted_elements and time_reduction_step <= max_reduction_steps): print(" *************************************************** ") print("inverted element found ... reducing the time step") (self.UlfUtils).ReduceTimeStep(self.combined_model_part, reduction_factor) (self.UlfUtils).ReduceTimeStep(self.fluid_model_part, reduction_factor) (self.UlfUtils).ReduceTimeStep(self.structure_model_part, reduction_factor) print("reduction_step = ", time_reduction_step) time_reduction_step = time_reduction_step + 1 # copying vars from the old step # for node in (self.combined_model_part).Nodes: # pold = node.GetSolutionStepValue(PRESSURE,1); # dispold = node.GetSolutionStepValue(DISPLACEMENT,1); # velold = node.GetSolutionStepValue(VELOCITY,1); # accold = node.GetSolutionStepValue(ACCELERATION,1); # # node.SetSolutionStepValue(PRESSURE,0,pold); # node.SetSolutionStepValue(DISPLACEMENT,0,dispold); # node.SetSolutionStepValue(VELOCITY,0,velold); # node.SetSolutionStepValue(ACCELERATION,0,accold); self.solver.MoveMesh() print("time step reduction completed") print(" *************************************************** ") (self.solver).Solve(self.domain_size, self.UlfUtils) [inverted_elements, vol] = self.CheckForInvertedElements() # if(inverted_elements == True): # # print "***********************************************************************" # print "***********************************************************************" # print "CRITICAL: ... element is still inverted after reducing the time step" # print "***********************************************************************" # print "***********************************************************************" # factor = 2.0**5 #this is the original time step # (self.UlfUtils).ReduceTimeStep(self.combined_model_part,factor); # (self.UlfUtils).ReduceTimeStep(self.fluid_model_part,factor); # (self.UlfUtils).ReduceTimeStep(self.structure_model_part,factor); # # for node in (self.combined_model_part).Nodes: # pold = node.GetSolutionStepValue(PRESSURE,1); # dispold = node.GetSolutionStepValue(DISPLACEMENT,1); # velold = node.GetSolutionStepValue(VELOCITY,1); # accold = node.GetSolutionStepValue(ACCELERATION,1); # # node.SetSolutionStepValue(PRESSURE,0,pold); # node.SetSolutionStepValue(DISPLACEMENT,0,dispold); # node.SetSolutionStepValue(VELOCITY,0,velold); # node.SetSolutionStepValue(ACCELERATION,0,accold); # # self.solver.MoveMesh() # # print "advancing in time without doing anything..." # (self.solver).PredictionStep(self.domain_size,self.UlfUtils) # print "pressure contribution process" - to be executed using exclusively fluid elements # and neighbouring relationships self.lagrangian_inlet_process.Execute() (self.fluid_neigh_finder).Execute() # print "injecting lagrangian inlet nodes - if given" #(self.UlfUtils).InjectNodesAtInlet(self.fluid_model_part, self.lagrangian_inlet_model_part, 0.50, 0.0, 0.0, 0.01) # moving the nodes #(self.UlfUtils).MoveInletNodes(self.fluid_model_part, 0.50, 0.0, 0.0) self.Remesh() # # the parameter in this function is set to 1 IN CASE WE DO NOT WANT TO CREATE THE NEW MESH, BUT JUST # the operations on model part # This is done to make switching off/on of remeshing easier def Remesh(self): # erase all conditions and elements prior to remeshing # self.UlfUtils.MarkNodesCloseToWall(self.fluid_model_part, self.domain_size, 2.50) self.PfemUtils.MarkNodesTouchingWall(self.fluid_model_part, self.domain_size, 0.1) # if (self.remeshing_flag==1.0): ((self.combined_model_part).Elements).clear() ((self.combined_model_part).Conditions).clear() ((self.combined_model_part).Nodes).clear() ((self.fluid_model_part).Elements).clear() ((self.fluid_model_part).Conditions).clear() # mark outer nodes for erasing (self.mark_outer_nodes_process).MarkOuterNodes(self.box_corner1, self.box_corner2) # adaptivity=True h_factor = 0.2 # 5 #0.5 # if (self.remeshing_flag==1.0): if (self.domain_size == 2): (self.Mesher).ReGenerateMesh("UpdatedLagrangianFluid2Dinc", "Condition2D", self.fluid_model_part, self.node_erase_process, True, self.add_nodes, self.alpha_shape, h_factor) elif (self.domain_size == 3): (self.Mesher).ReGenerateMesh("UpdatedLagrangianFluid3Dinc", "Condition3D", self.fluid_model_part, self.node_erase_process, True, self.add_nodes, self.alpha_shape, h_factor) # remesh CHECK for 3D or 2D # calculating fluid neighbours before applying boundary conditions (self.fluid_neigh_finder).Execute() (self.condition_neigh_finder).Execute() # (self.UlfUtils).CalculateNodalArea(self.fluid_model_part,self.domain_size); # print "marking fluid" and applying fluid boundary conditions (self.ulf_apply_bc_process).Execute() (self.mark_fluid_process).Execute() # saving structural conditions - walls #(self.save_structure_conditions_process).SaveStructureConditions(self.fluid_model_part, self.structure_model_part, self.domain_size); # merging the structural elements back (they are saved in the Initialize) (self.merge_model_parts_process).MergeParts(self.fluid_model_part, self.structure_model_part, self.combined_model_part) # calculating the neighbours for the overall model (self.combined_neigh_finder).Execute() (self.UlfUtils).CalculateNodalArea(self.fluid_model_part, self.domain_size) # # only for the bladder example, remove next 2 lines otherwise (there I delete lonely nodes) # self.UlfUtils.MarkLonelyNodesForErasing(self.fluid_model_part, self.domain_size) # self.node_erase_process.Execute() print("end of remesh fucntion") # # def FindNeighbours(self): (self.neigh_finder).Execute()
class ULF_FSISolver: def __init__(self, out_file, fluid_only_model_part, fluid_model_part, structure_model_part, combined_model_part, FSI, compute_reactions, box_corner1, box_corner2, domain_size, add_nodes, bulk_modulus, density): self.out_file = out_file self.compute_reactions = compute_reactions self.domain_size = domain_size; self.echo_level = 0 self.counter = int(0) # TO REMESH OR NOT: 0 - no remeshing, 1 - remeshing self.add_nodes = bool(add_nodes) self.FSI = bool(FSI) # K - the bulk modulus self.bulk_modulus = bulk_modulus self.density = density # saving the different model parts self.combined_model_part = combined_model_part; # contains both structure and fluid self.fluid_model_part = fluid_model_part; # contains only fluid elements, but all nodes! self.structure_model_part = structure_model_part; # contains only structural elements self.fluid_only_model_part = fluid_only_model_part; # contains only fluid elements and nodes # time integration scheme (dam_factor= alpha_bossak) self.damp_factor = -0.3 self.time_scheme = ResidualBasedPredictorCorrectorBossakScheme(self.damp_factor) # definition of the solvers self.pres_time_scheme = ResidualBasedIncrementalUpdateStaticScheme() self.pres_linear_solver = CGSolver(1e-3, 1000) # SkylineLUFactorizationSolver() # definition of the convergence criteria self.conv_criteria = DisplacementCriteria(1e-6,1e-9) #self.conv_criteria = IncrementalDisplacementCriteria(1e-3, 1e-6) # self.pressure_calculate_process = PressureCalculateProcess(fluid_model_part,domain_size); self.ulf_apply_bc_process = UlfApplyBCProcess(fluid_model_part); self.ulf_time_step_dec_process = UlfTimeStepDecProcess(fluid_model_part); self.mark_fluid_process = MarkFluidProcess(fluid_model_part); self.mark_close_nodes_process = MarkCloseNodesProcess(fluid_model_part); self.mark_outer_nodes_process = MarkOuterNodesProcess(fluid_model_part); self.node_erase_process = NodeEraseProcess(fluid_model_part); # tools to save and merge the structural contributions self.save_structure_model_part_process = SaveStructureModelPartProcess(); self.save_structure_conditions_process = SaveStructureConditionsProcess(); self.merge_model_parts_process = MergeModelPartsProcess(); # this will save fluid only model part self.save_fluid_only_process = SaveFluidOnlyProcess(); # temporary ... i need it to calculate the nodal area self.UlfUtils = UlfUtils() self.PfemUtils = PfemUtils() # self.save_structural_elements self.alpha_shape = 1.5; self.h_multiplier = 0.1 # saving the limits of the box (all the nodes external to this will be erased) self.box_corner1 = box_corner1 self.box_corner2 = box_corner2 if(domain_size == 2): # self.Mesher = TriGenModeler() self.Mesher = TriGenPFEMModeler() self.combined_neigh_finder = FindNodalNeighboursProcess(combined_model_part, 9, 18) self.fluid_neigh_finder = FindNodalNeighboursProcess(fluid_model_part, 9, 18) self.fluid_only_neigh_finder = FindNodalNeighboursProcess(fluid_only_model_part, 9, 18) # this is needed if we want to also store the conditions a node belongs to self.condition_neigh_finder = FindConditionsNeighboursProcess(fluid_model_part, 2, 10) elif (domain_size == 3): # improved mesher self.Mesher = TetGenPfemModeler() # self.Mesher = TetGenModeler() self.combined_neigh_finder = FindNodalNeighboursProcess(combined_model_part, 20, 30) self.fluid_neigh_finder = FindNodalNeighboursProcess(fluid_model_part, 20, 30) self.fluid_only_neigh_finder = FindNodalNeighboursProcess(fluid_only_model_part, 20, 30) # this is needed if we want to also store the conditions a node belongs to self.condition_neigh_finder = FindConditionsNeighboursProcess(fluid_model_part, 3, 20) print("after reading all the model contains:") print(self.fluid_model_part) # detect initial size distribution - note that initially the fluid model part contains # all the elements of both structure and fluid ... this is only true after reading the input (self.fluid_neigh_finder).Execute(); self.Hfinder = FindNodalHProcess(fluid_model_part); self.Hfinder.Execute(); self.ResetNodalHAtLonelyNodes() #assigning average nodal h to lonely nodes self.AssignHtoLonelyStructureNodes() # # delta time estimation based on the non-negativity of the jacobian def EstimateDeltaTime(self, max_dt, domain_size): # return (self.UlfUtils).EstimateDeltaTime(min_dt,max_dt,self.combined_model_part) return (self.ulf_time_step_dec_process).EstimateDeltaTime(max_dt, domain_size) # # this function is needed only in case there is a lagrangian nodes-inlet in the problem # three numbers - are veolicties in x y and z directions # def MoveInletNodes(self, model_part): # (self.UlfUtils).MoveInletNodes(self.fluid_model_part, 0.1, 0.0, 0.0) # def Initialize(self): # creating the solution strategy CalculateReactionFlag = bool(self.compute_reactions) ReformDofSetAtEachStep = True MoveMeshFlag = True import ulf_frac_strategy self.solver = ulf_frac_strategy.ULFFracStrategyPython(self.fluid_only_model_part, self.combined_model_part, self.fluid_model_part, self.time_scheme, self.pres_time_scheme, self.pres_linear_solver, self.conv_criteria, CalculateReactionFlag, ReformDofSetAtEachStep, MoveMeshFlag, self.domain_size, self.bulk_modulus, self.density) print("self.echo_level = ", self.echo_level) (self.solver).SetEchoLevel(self.echo_level) print("finished initialization of the fluid strategy") # saving the structural elements (self.mark_fluid_process).Execute(); # we need this before saving the structrural elements # we specify domain size, to deal with problems involving membarnes in 3D in a specific way (see save_structure_model_part_process.h (self.save_structure_model_part_process).SaveStructure(self.fluid_model_part, self.structure_model_part); print("STRUCTURE PART!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", self.structure_model_part) #(self.save_structure_conditions_process).SaveStructureConditions(self.fluid_model_part, self.structure_model_part, self.domain_size); # creating initially empty container for lagrangian inlet-nodes # marking the fluid (self.fluid_neigh_finder).Execute(); (self.combined_neigh_finder).Execute(); (self.ulf_apply_bc_process).Execute(); (self.mark_fluid_process).Execute(); # caluclating nodal area in order to calculate pressures (self.UlfUtils).CalculateNodalArea(self.fluid_model_part, self.domain_size); # remeshing before the first solution self.Remesh(); # def CheckForInvertedElements(self): volume = (self.UlfUtils).CalculateVolume(self.combined_model_part, self.domain_size) inverted_elements = False if(volume < 0.0): volume = - volume inverted_elements = True return [inverted_elements, volume] # def Solve(self, lagrangian_inlet_process): self.lagrangian_inlet_process = lagrangian_inlet_process print("solving the fluid problem") inverted_elements = (self.solver).Solve(self.domain_size, self.UlfUtils, self.FSI) print("successful solution of the fluid ") reduction_factor = 0.5 max_reduction_steps = 5 time_reduction_step = 0 while(inverted_elements and time_reduction_step <= max_reduction_steps): print(" *************************************************** ") print("inverted element found ... reducing the time step") (self.UlfUtils).ReduceTimeStep(self.combined_model_part, reduction_factor); (self.UlfUtils).ReduceTimeStep(self.fluid_model_part, reduction_factor); (self.UlfUtils).ReduceTimeStep(self.structure_model_part, reduction_factor); print("reduction_step = ", time_reduction_step) time_reduction_step = time_reduction_step + 1 self.solver.MoveMesh() print("time step reduction completed") print(" *************************************************** ") (self.solver).Solve(self.domain_size, self.UlfUtils, self.FSI) [inverted_elements, vol] = self.CheckForInvertedElements() if(inverted_elements): print("***********************************************************************") print("***********************************************************************") print("CRITICAL: ... element is still inverted after reducing the time step") print("***********************************************************************") print("***********************************************************************") factor = 2.0 ** 5 # this is the original time step (self.UlfUtils).ReduceTimeStep(self.combined_model_part, factor); (self.UlfUtils).ReduceTimeStep(self.fluid_model_part, factor); (self.UlfUtils).ReduceTimeStep(self.structure_model_part, factor); self.solver.MoveMesh() print("advancing in time without doing anything...") (self.solver).PredictionStep(self.domain_size, self.UlfUtils) self.lagrangian_inlet_process.Execute() (self.fluid_neigh_finder).Execute(); self.Remesh(); # # the parameter in this function is set to 1 IN CASE WE DO NOT WANT TO CREATE THE NEW MESH, BUT JUST # the operations on model part # This is done to make switching off/on of remeshing easier def Remesh(self): timeRemesh = time.time() # preventing the nodes from coming tooo close to wall self.PfemUtils.MarkNodesTouchingWall(self.fluid_model_part, self.domain_size, 0.08) # erase all conditions and elements prior to remeshing ((self.combined_model_part).Elements).clear(); ((self.combined_model_part).Conditions).clear(); ((self.combined_model_part).Nodes).clear(); ((self.fluid_model_part).Elements).clear(); ((self.fluid_model_part).Conditions).clear(); # self.UlfUtils.MarkNodesCloseToWall(self.fluid_model_part, self.domain_size, 2.5000) # mark outer nodes for erasing (self.mark_outer_nodes_process).MarkOuterNodes(self.box_corner1, self.box_corner2); # adaptivity=True h_factor = 0.2 if (self.domain_size == 2): h_factor = 0.25 (self.Mesher).ReGenerateMesh("UlfFrac2D", "Condition2D", self.fluid_model_part, self.node_erase_process, True, self.add_nodes, self.alpha_shape, h_factor) elif (self.domain_size == 3): (self.Mesher).ReGenerateMesh("UlfFrac3D", "Condition3D", self.fluid_model_part, self.node_erase_process, True, self.add_nodes, self.alpha_shape, h_factor) # calculating fluid neighbours before applying boundary conditions (self.fluid_neigh_finder).Execute(); (self.condition_neigh_finder).Execute(); # print "marking fluid" and applying fluid boundary conditions (self.ulf_apply_bc_process).Execute(); (self.mark_fluid_process).Execute(); # merging the structural elements back (they are saved in the Initialize) (self.merge_model_parts_process).MergeParts(self.fluid_model_part, self.structure_model_part, self.combined_model_part); # this one is used to perfrom some operations exclusively on the fluid elements/nodes (self.save_fluid_only_process).SaveFluidOnly(self.fluid_model_part, self.fluid_only_model_part); print(self.fluid_model_part) print(self.fluid_only_model_part) print(self.combined_model_part) # calculating the neighbours for the overall model (self.combined_neigh_finder).Execute(); #(self.fluid_only_neigh_finder).Execute(); (self.UlfUtils).CalculateNodalArea(self.fluid_model_part, self.domain_size); self.UlfUtils.MarkLonelyNodesForErasing(self.fluid_model_part) self.node_erase_process.Execute() (self.mark_fluid_process).Execute(); timeRemeshEnd = time.time() print("Remeshing took ", str(timeRemeshEnd - timeRemesh)) print("end of remesh function") # # def FindNeighbours(self): (self.neigh_finder).Execute(); #this function is included since at the findNodalHProcess of Kratos core assigns max value (1.7*e^309) to all nodes #and then computes the correct value only for the nodes of elements. Thus lonely nodes remain with this enormous values def ResetNodalHAtLonelyNodes(self): for node in self.fluid_model_part.Nodes: if (node.GetSolutionStepValue(NODAL_H)>100000000.0): node.SetSolutionStepValue(NODAL_H,0,0.0) ###################################################################### def AssignHtoLonelyStructureNodes(self): nnodes=0 nodal_h=0.0 av_nodal_h=0.0 for node in self.fluid_model_part.Nodes: if (node.GetSolutionStepValue(NODAL_H)!=0.0): nnodes=nnodes+1; nodal_h=nodal_h+node.GetSolutionStepValue(NODAL_H); av_nodal_h=nodal_h/nnodes for node in self.fluid_model_part.Nodes: if (node.GetSolutionStepValue(IS_STRUCTURE)==1.0 and node.GetSolutionStepValue(IS_FLUID)==0.0): node.SetSolutionStepValue(NODAL_H, av_nodal_h)