-
Notifications
You must be signed in to change notification settings - Fork 247
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Auto stash before merge of "Kratos_RotatingFrameProcess" and "origin/…
…Kratos_RotatingFrameProcess"
- Loading branch information
Showing
5 changed files
with
819 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
181 changes: 181 additions & 0 deletions
181
kratos/python_scripts/assign_rotational_symmetry_master_slave_constraints_process
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
import KratosMultiphysics as KM | ||
import numpy as np | ||
import math | ||
|
||
def Factory(settings, model): | ||
if not isinstance(settings, KM.Parameters): | ||
raise Exception("expected input shall be a Parameters object, encapsulating a json string") | ||
return AssignRotationalSymmetryMasterSlaveConstraintsProcess(model, settings["Parameters"]) | ||
|
||
## All the processes python should be derived from "Process" | ||
class AssignRotationalSymmetryMasterSlaveConstraintsProcess(KM.Process): | ||
"""The process facilitates the discovery of neighboring nodes in a | ||
master model part within a designated radius for each node in the | ||
slave model part. Following this, it establishes a master-slave constraint | ||
and calculates its weights using a spatial function that employs radial basis functions. | ||
|
||
Public member variables: | ||
model -- the container of the different model parts. | ||
settings -- Kratos parameters containing process settings. | ||
""" | ||
|
||
def __init__(self, model, settings): | ||
""" The default constructor of the class | ||
|
||
Keyword arguments: | ||
self -- It signifies an instance of a class. | ||
Model -- the container of the different model parts. | ||
settings -- Kratos parameters containing process settings. | ||
""" | ||
KM.Process.__init__(self) # calling the baseclass constructor | ||
|
||
default_settings = KM.Parameters("""{ | ||
"model_part_name": "", | ||
"slave_model_part_name": "", | ||
"master_model_part_name": "", | ||
"variable_names": [], | ||
"search_radius": 1.0, | ||
"minimum_number_of_neighbouring_nodes": 3, | ||
"reform_constraints_at_each_step": false | ||
}""") | ||
|
||
# Add missing settings that the user did not provide but that | ||
# are necessary for this process | ||
settings.ValidateAndAssignDefaults(default_settings) | ||
|
||
# Get the model part on which the MasterSlaveConstraints are going to be applied | ||
if not settings["model_part_name"].GetString(): | ||
raise Exception("\'model_part_name\' not provided. Please specify the model part to apply to MasterSlaveConstraints to.") | ||
model_part_name = settings["model_part_name"].GetString() #MasterSlaveConstraints are applied to computing model part | ||
self.computing_model_part = model.GetModelPart(model_part_name) | ||
|
||
# Get the slave model part | ||
if not settings["slave_model_part_name"].GetString(): | ||
raise Exception("\'slave_model_part_name\' not provided. Please specify the slave model part.") | ||
slave_model_part_name = settings["slave_model_part_name"].GetString() | ||
self.slave_model_part = model.GetModelPart(slave_model_part_name) | ||
|
||
# Get the master model part | ||
if not settings["master_model_part_name"].GetString(): | ||
raise Exception("\'master_model_part_name\' not provided. Please specify the master model part.") | ||
master_model_part_name = settings["master_model_part_name"].GetString() | ||
self.master_model_part = model.GetModelPart(master_model_part_name) | ||
|
||
# Search radius for the MasterSlaveConstraints | ||
self.search_radius = settings["search_radius"].GetDouble() | ||
|
||
# Minimum number of neighboring nodes retrieved from the search radius | ||
self.minimum_number_of_neighbouring_nodes = settings["minimum_number_of_neighbouring_nodes"].GetInt() | ||
|
||
# Apply MasterSlaveConstraints at each time step (True) or only once (False) | ||
self.reform_constraints_at_each_step = settings["reform_constraints_at_each_step"].GetBool() | ||
|
||
# Retrieve and check if variables exist | ||
variable_names = settings["variable_names"].GetStringArray() | ||
if len(variable_names) == 0: | ||
err_msg = "The variable names need to be specified by the user in the \'variable_names\' string array." | ||
raise Exception(err_msg) | ||
if any(variable_names.count(var_name) > 1 for var_name in variable_names): | ||
err_msg = "There are repeated variables in the \'variable_names\' string array." | ||
raise Exception(err_msg) | ||
variable_names.sort() | ||
|
||
self.variables_list = [] # Initialize the list of variables | ||
|
||
for var_name in variable_names: | ||
# Check if the variable exists in KratosGlobals | ||
if not KM.KratosGlobals.HasVariable(var_name): | ||
err_msg = "\'{}\' variable in \'variable_names\' is not in KratosGlobals. Please check the provided value.".format(var_name) | ||
|
||
var_type = KM.KratosGlobals.GetVariableType(var_name) # Get the type of the variable | ||
|
||
# Check the variable type and add it to the variables_list accordingly | ||
if var_type == "Array": | ||
domain_size = self.computing_model_part.ProcessInfo[KM.DOMAIN_SIZE] # Get the domain size from the ProcessInfo | ||
component_suffixes = ["_X", "_Y", "_Z"] # Suffixes for the components of the array variable | ||
for i in range(domain_size): | ||
var_name_with_suffix = f"{var_name}{component_suffixes[i]}" # Append the component suffix to the variable name | ||
self.variables_list.append(KM.KratosGlobals.GetVariable(var_name_with_suffix)) # Add the variable to the list | ||
elif var_type == "Double": | ||
self.variables_list.append(KM.KratosGlobals.GetVariable(var_name)) # Add the variable to the list | ||
else: | ||
raise Exception("Variable " + var_name + " not compatible") # Raise an exception for incompatible variable types | ||
|
||
# Initialization of ghost nodes related attributes | ||
self.model.CreateModelPart("AuxiliarMasterModelPart") | ||
self.aux_master_model_part = self.model.GetModelPart("AuxiliarMasterModelPart") | ||
self.max_node_id = self.computing_model_part.NumberOfNodes() | ||
|
||
def ExecuteInitialize(self): | ||
""" This method is executed at the begining to initialize the process | ||
|
||
Keyword arguments: | ||
self -- It signifies an instance of a class. | ||
""" | ||
|
||
self.__CreateGhostNodes(self.master_model_part.Nodes) | ||
|
||
# Initialize MasterSlaveConstraints to neighbours utility | ||
self.assign_mscs_utility = KM.AssignMasterSlaveConstraintsToNeighboursUtility(self.master_model_part.Nodes) | ||
|
||
# The user may only need to set up the MasterSlaveConstraints only once | ||
if not self.reform_constraints_at_each_step: | ||
for variable in self.variables_list: | ||
self.assign_mscs_utility.AssignMasterSlaveConstraintsToNodes(self.slave_model_part.Nodes,self.search_radius,self.computing_model_part, variable, self.minimum_number_of_neighbouring_nodes) | ||
|
||
|
||
def ExecuteInitializeSolutionStep(self): | ||
""" This method is executed in order to initialize the current step | ||
|
||
Keyword arguments: | ||
self -- It signifies an instance of a class. | ||
""" | ||
# If the user want the mscs to be updated at each time step, this is usefull for moving meshes. | ||
if self.reform_constraints_at_each_step: | ||
self.assign_mscs_utility.AssignMasterSlaveConstraintsToNodes(self.slave_model_part.Nodes,self.search_radius,self.computing_model_part, self.variables_list, self.minimum_number_of_neighbouring_nodes) | ||
|
||
def ExecuteFinalizeSolutionStep(self): | ||
""" This method is executed in order to finalize the current step | ||
|
||
Keyword arguments: | ||
self -- It signifies an instance of a class. | ||
""" | ||
# If MasterSlaveConstraints are updated every time step, these are to me removed before being re-assigned. | ||
if self.reform_constraints_at_each_step: | ||
self.__RemoveConstraints() | ||
|
||
def __RemoveConstraints(self): | ||
#Remove master-slave constraints | ||
KM.VariableUtils().SetFlag(KM.TO_ERASE, True, self.computing_model_part.MasterSlaveConstraints) | ||
self.computing_model_part.RemoveMasterSlaveConstraintsFromAllLevels(KM.TO_ERASE) | ||
|
||
def __CreateGhostNodes(self, nodes): | ||
"""Create ghost nodes for each node.""" | ||
ghost_to_original_mapping = {} | ||
rotation_angles = [0, 60, 120, 180, 240, 300] | ||
|
||
self.max_node_id = self.main_model_part.NumberOfNodes() | ||
|
||
for angle in rotation_angles: | ||
# Create ghost nodes | ||
for original_node in nodes: | ||
ghost_node = self.__RotateNode(original_node, angle) | ||
ghost_to_original_mapping[ghost_node] = original_node | ||
self.aux_master_model_part.AddNode(ghost_node) | ||
|
||
return ghost_to_original_mapping | ||
|
||
def __RotateNode(self, original_node, angle_degrees): | ||
"""Rotate a node by a given angle (in degrees) about the origin.""" | ||
angle_radians = math.radians(angle_degrees) | ||
|
||
# Apply 2D rotation matrix | ||
new_x = original_node.X * math.cos(angle_radians) - original_node.Y * math.sin(angle_radians) | ||
new_y = original_node.X * math.sin(angle_radians) + original_node.Y * math.cos(angle_radians) | ||
|
||
# Generate a new node ID based on the maximum node ID | ||
new_node_id = self.max_node_id + 1 | ||
self.max_node_id += 1 | ||
|
||
# Create the new node with the ID and coordinates | ||
return KM.Node(new_node_id, new_x, new_y, 0.0) |
Oops, something went wrong.