From 37240f878d42d71ce260e5280fc3bf354902908a Mon Sep 17 00:00:00 2001 From: SADPR Date: Tue, 5 Dec 2023 21:12:08 +0100 Subject: [PATCH] Revert "Auto stash before merge of "Kratos_RotatingFrameProcess" and "origin/Kratos_RotatingFrameProcess"" This reverts commit 5be37fedc1ab27dadab5387178a6f2d58f2e2d63. --- .../add_geometrical_utilities_to_python.cpp | 2 - ..._symmetry_master_slave_constraints_process | 181 --------- ...mmetry_master_slave_constraints_process.py | 182 --------- ...lave_constraints_to_neighbours_utility.cpp | 383 +----------------- ..._slave_constraints_to_neighbours_utility.h | 76 +--- 5 files changed, 5 insertions(+), 819 deletions(-) delete mode 100644 kratos/python_scripts/assign_rotational_symmetry_master_slave_constraints_process delete mode 100644 kratos/python_scripts/assign_rotational_symmetry_master_slave_constraints_process.py diff --git a/kratos/python/add_geometrical_utilities_to_python.cpp b/kratos/python/add_geometrical_utilities_to_python.cpp index 82972ff5c113..f2913ad0c6c7 100644 --- a/kratos/python/add_geometrical_utilities_to_python.cpp +++ b/kratos/python/add_geometrical_utilities_to_python.cpp @@ -439,8 +439,6 @@ void AddGeometricalUtilitiesToPython(pybind11::module &m) .def(py::init()) .def("AssignMasterSlaveConstraintsToNodes", [](AssignMasterSlaveConstraintsToNeighboursUtility& rAssignMasterSlaveConstraintsToNeighboursUtility, NodesContainerType pNodes, double const Radius, ModelPart& rComputingModelPart, const std::vector>>& rVariableList, double const MinNumOfNeighNodes){ return rAssignMasterSlaveConstraintsToNeighboursUtility.AssignMasterSlaveConstraintsToNodes(pNodes, Radius, rComputingModelPart, rVariableList, MinNumOfNeighNodes);}) - .def("AssignRotationalMasterSlaveConstraintsToNodes", [](AssignMasterSlaveConstraintsToNeighboursUtility& rAssignMasterSlaveConstraintsToNeighboursUtility, NodesContainerType pNodes, double const Radius, ModelPart& rComputingModelPart, const std::vector>>& rVariableList, double const MinNumOfNeighNodes, const std::unordered_map>& GhostToOriginalMapping){ - return rAssignMasterSlaveConstraintsToNeighboursUtility.AssignRotationalMasterSlaveConstraintsToNodes(pNodes, Radius, rComputingModelPart, rVariableList, MinNumOfNeighNodes, GhostToOriginalMapping);}) ; } diff --git a/kratos/python_scripts/assign_rotational_symmetry_master_slave_constraints_process b/kratos/python_scripts/assign_rotational_symmetry_master_slave_constraints_process deleted file mode 100644 index 720de7016de3..000000000000 --- a/kratos/python_scripts/assign_rotational_symmetry_master_slave_constraints_process +++ /dev/null @@ -1,181 +0,0 @@ -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) \ No newline at end of file diff --git a/kratos/python_scripts/assign_rotational_symmetry_master_slave_constraints_process.py b/kratos/python_scripts/assign_rotational_symmetry_master_slave_constraints_process.py deleted file mode 100644 index 54f4824552e3..000000000000 --- a/kratos/python_scripts/assign_rotational_symmetry_master_slave_constraints_process.py +++ /dev/null @@ -1,182 +0,0 @@ -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 - }""") - - # 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() - - # 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 - model.CreateModelPart("AuxiliarMasterModelPart") - self.aux_master_model_part = 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. - """ - - # Create ghost nodes in the master model part - self.__CreateGhostNodes(self.master_model_part.Nodes) - - # Initialize MasterSlaveConstraints to neighbours utility with the master model part nodes (which now includes ghost nodes) - self.assign_mscs_utility = KM.AssignMasterSlaveConstraintsToNeighboursUtility(self.aux_master_model_part.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. - """ - # Assign dynamically the master-slave constraints - # 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) - self.assign_mscs_utility.AssignRotationalMasterSlaveConstraintsToNodes(self.slave_model_part.Nodes, self.search_radius, self.computing_model_part, self.variables_list, self.minimum_number_of_neighbouring_nodes, self.ghost_to_original_mapping) - - def ExecuteFinalizeSolutionStep(self): - """ This method is executed in order to finalize the current step - - Keyword arguments: - self -- It signifies an instance of a class. - """ - # Since MasterSlaveConstraints are updated every time step, they need to be removed before being re-assigned. - 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 by rotating them about the origin. - - Keyword arguments: - nodes -- The nodes to be rotated to create the ghost nodes. - """ - self.ghost_to_original_mapping = {} # Initialize the mapping as an attribute of the class - rotation_angles = [0, -60, -120, -180, -240, -300] - self.max_node_id = self.computing_model_part.NumberOfNodes() - - for angle in rotation_angles: - # Create ghost nodes - for original_node in nodes: - ghost_node = self.__RotateNode(original_node, angle) - # Store the mapping using node IDs and the rotation angle - self.ghost_to_original_mapping[ghost_node.Id] = (original_node.Id, np.pi*angle/180) - if original_node.Id==922: - print(angle) - print(ghost_node.Id) - self.aux_master_model_part.AddNode(ghost_node) - - - def __RotateNode(self, original_node, angle_degrees): - """Rotate a node by a given angle (in degrees) about the origin. - - Keyword arguments: - original_node -- The node to be rotated. - angle_degrees -- The angle in degrees by which the node is to be rotated. - """ - 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) \ No newline at end of file diff --git a/kratos/utilities/assign_master_slave_constraints_to_neighbours_utility.cpp b/kratos/utilities/assign_master_slave_constraints_to_neighbours_utility.cpp index 6c2a92ad7f0e..dbfd9b00f0c1 100644 --- a/kratos/utilities/assign_master_slave_constraints_to_neighbours_utility.cpp +++ b/kratos/utilities/assign_master_slave_constraints_to_neighbours_utility.cpp @@ -131,7 +131,7 @@ void AssignMasterSlaveConstraintsToNeighboursUtility::GetDofsAndCoordinatesForCl // Loop over the cloud of nodes for (std::size_t i = 0; i < CloudOfNodesArray.size(); i++) { - auto p_slave_node = CloudOfNodesArray[i];//////CHANGE SLAVE NODE NAME + auto p_slave_node = CloudOfNodesArray[i]; // Loop over the variable list for (std::size_t j = 0; j < rVariableList.size(); j++) { @@ -154,99 +154,6 @@ void AssignMasterSlaveConstraintsToNeighboursUtility::GetDofsAndCoordinatesForCl KRATOS_CATCH(""); } -void AssignMasterSlaveConstraintsToNeighboursUtility::GetDofsAndCoordinatesForCloudOfNodesFlattened( - const ResultNodesContainerType& CloudOfNodesArray, - const std::vector>>& rVariableList, - DofPointerVectorType& rCloudOfDofs, - Matrix& rCloudOfNodesCoordinates -) -{ - KRATOS_TRY; - - // Resize rCloudOfDofs to accommodate all DOFs for all variables - rCloudOfDofs.resize(rVariableList.size() * CloudOfNodesArray.size()); - - // Resize rCloudOfNodesCoordinates to match the size of the cloud of nodes - rCloudOfNodesCoordinates.resize(CloudOfNodesArray.size(), 3); - - // Loop over the cloud of nodes - for (std::size_t i = 0; i < CloudOfNodesArray.size(); i++) { - auto p_slave_node = CloudOfNodesArray[i]; - - // Loop over the variable list - for (std::size_t j = 0; j < rVariableList.size(); j++) { - const auto& r_variable = rVariableList[j]; - - // Check if the slave node has the required DOF for the current variable - if (p_slave_node->HasDofFor(r_variable.get())) { - std::size_t counter = i * rVariableList.size() + j; - rCloudOfDofs[counter] = p_slave_node->pGetDof(r_variable.get()); - } else { - KRATOS_ERROR << "The node with ID " << p_slave_node->Id() << " does not have the required DOF for the variable " << r_variable.get().Name() << std::endl; - } - } - - // Assign the coordinates of the slave node to the corresponding row in rCloudOfNodesCoordinates - noalias(row(rCloudOfNodesCoordinates, i)) = p_slave_node->Coordinates(); - } - - KRATOS_CATCH(""); -} - -struct CustomComparator { - static constexpr double TOLERANCE = 1e-6; - - bool operator()(const std::tuple& a, const std::tuple& b) const { - return std::fabs(std::get<0>(a) - std::get<0>(b)) > TOLERANCE || - std::fabs(std::get<1>(a) - std::get<1>(b)) > TOLERANCE || - std::fabs(std::get<2>(a) - std::get<2>(b)) > TOLERANCE; - } -}; - -void AssignMasterSlaveConstraintsToNeighboursUtility::FilterUniqueNodesForRBF( - ResultNodesContainerType& CloudOfNodesArray, - Matrix& rCloudOfNodesCoordinates -) { - KRATOS_TRY; - - // Use a set with a custom comparator to keep track of unique coordinates - std::set, CustomComparator> unique_coords; - - // Temporary vector to store unique nodes - std::vector temp_nodes; - - // Loop over the cloud of nodes - for (auto& p_node : CloudOfNodesArray) { - auto coords = p_node->Coordinates(); - std::tuple current_coords(coords[0], coords[1], coords[2]); - - // Check if the coordinates are unique - if (unique_coords.find(current_coords) == unique_coords.end()) { - unique_coords.insert(current_coords); - temp_nodes.push_back(p_node); - } - } - - // Clear the original CloudOfNodesArray and repopulate with unique nodes - CloudOfNodesArray.clear(); - for (auto& p_node : temp_nodes) { - CloudOfNodesArray.push_back(p_node); - } - - // Resize rCloudOfNodesCoordinates to match the size of unique nodes - rCloudOfNodesCoordinates.resize(temp_nodes.size(), 3); - - // Fill rCloudOfNodesCoordinates with unique coordinates - for (std::size_t i = 0; i < temp_nodes.size(); i++) { - auto coords = temp_nodes[i]->Coordinates(); - for (std::size_t j = 0; j < 3; j++) { - rCloudOfNodesCoordinates(i, j) = coords[j]; - } - } - - KRATOS_CATCH(""); -} - void AssignMasterSlaveConstraintsToNeighboursUtility::AssignMasterSlaveConstraintsToNodes( NodesContainerType pSlaveNodes, double const Radius, @@ -309,12 +216,6 @@ void AssignMasterSlaveConstraintsToNeighboursUtility::AssignMasterSlaveConstrain constant_vector.resize(r_n_container.size()); IndexType it = i.fetch_add(1) * rVariableList.size(); // Atomically increment the counter and get the previous value - if (p_slave_node->Id() == 929){ - KRATOS_WATCH(r_cloud_of_nodes) - KRATOS_WATCH(r_n_container) - KRATOS_WATCH(shape_matrix) - } - for (std::size_t j = 0; j < rVariableList.size(); ++j) { concurrent_constraints.enqueue(r_clone_constraint.Create(prev_num_mscs + it + j + 1, const_cast(r_cloud_of_dofs[j]), r_slave_dofs[j], shape_matrix, constant_vector)); } @@ -335,288 +236,6 @@ void AssignMasterSlaveConstraintsToNeighboursUtility::AssignMasterSlaveConstrain KRATOS_CATCH(""); } -void AssignMasterSlaveConstraintsToNeighboursUtility::AssignRotationalMasterSlaveConstraintsToNodes( - NodesContainerType pSlaveNodes, - double const Radius, - ModelPart& rComputingModelPart, - const std::vector>>& rVariableList, - double const MinNumOfNeighNodes, - const std::unordered_map>& GhostToOriginalMapping -) -{ - KRATOS_TRY; - - BuiltinTimer build_and_assign_mscs; - - thread_local std::vector r_cloud_of_dofs; - thread_local DofPointerVectorType r_cloud_of_master_dofs; - thread_local std::vector r_slave_dofs; - thread_local Matrix r_cloud_of_nodes_coordinates; - thread_local Matrix r_cloud_of_master_nodes_coordinates; - thread_local array_1d r_slave_coordinates; - thread_local Vector r_n_container; - thread_local Vector constant_vector; - thread_local Matrix shape_matrix_x, shape_matrix_y, shape_matrix_z; - - int prev_num_mscs = rComputingModelPart.NumberOfMasterSlaveConstraints(); - - KRATOS_WARNING_IF("AssignRotationalMasterSlaveConstraintsToNodes", prev_num_mscs > 0) << "Previous Master-Slave Constraints exist in the ModelPart. The new Constraints may interact with the existing ones." << std::endl; - - auto& p_nodes_array = pSlaveNodes.GetContainer(); - - const auto& r_clone_constraint = KratosComponents::Get("LinearMasterSlaveConstraint"); - - using MasterSlaveConstraintQueue = moodycamel::ConcurrentQueue; - MasterSlaveConstraintQueue concurrent_constraints; - - std::atomic i(0); - - block_for_each(p_nodes_array, [&](Node::Pointer& p_slave_node) { - - // Skip nodes with IDs 1174 or 1015 950 1111 - if (p_slave_node->Id() == 1174 || p_slave_node->Id() == 1015) { - return; // Skip the current iteration of the loop - } - - double local_radius = Radius; - ResultNodesContainerType r_cloud_of_nodes(0); - ResultNodesContainerType r_local_results(mMaxNumberOfNodes); - - while (r_cloud_of_nodes.size() < MinNumOfNeighNodes) { - r_cloud_of_nodes.clear(); - SearchNodesInRadiusForNode(p_slave_node, local_radius, r_cloud_of_nodes, r_local_results); - local_radius += Radius; - } - - GetDofsAndCoordinatesForSlaveNode(p_slave_node, rVariableList, r_slave_dofs, r_slave_coordinates); - FilterUniqueNodesForRBF(r_cloud_of_nodes, r_cloud_of_nodes_coordinates); - - ResultNodesContainerType r_cloud_of_master_nodes; - r_cloud_of_master_nodes.reserve(r_cloud_of_nodes.size()); - for (auto& ghost_node : r_cloud_of_nodes) { - auto it = GhostToOriginalMapping.find(ghost_node->Id()); - if (it != GhostToOriginalMapping.end()) { - IndexType master_node_id = it->second.first; // Extracting the original/master node ID from the mapping - Node::Pointer p_master_node = rComputingModelPart.pGetNode(master_node_id); - r_cloud_of_master_nodes.push_back(p_master_node); - } else { - KRATOS_ERROR << "Ghost Node ID " << ghost_node->Id() << " not found in GhostToOriginalMapping!" << std::endl; - } - } - - GetDofsAndCoordinatesForCloudOfNodesFlattened(r_cloud_of_master_nodes, rVariableList, r_cloud_of_master_dofs, r_cloud_of_master_nodes_coordinates); - - RBFShapeFunctionsUtility::CalculateShapeFunctions(r_cloud_of_nodes_coordinates, r_slave_coordinates, r_n_container); - - Vector ListOfAngles; - ExtractAnglesFromMapping(r_cloud_of_nodes, GhostToOriginalMapping, ListOfAngles); - - ObtainShapeMatrix(shape_matrix_x, shape_matrix_y, shape_matrix_z, r_n_container, ListOfAngles); - constant_vector.resize(shape_matrix_x.size2()); - if (p_slave_node->Id() == 929){ - KRATOS_WATCH(r_cloud_of_nodes) - KRATOS_WATCH(r_cloud_of_nodes_coordinates) - KRATOS_WATCH(r_slave_coordinates) - KRATOS_WATCH(r_cloud_of_master_nodes) - KRATOS_WATCH(r_cloud_of_master_dofs) - KRATOS_WATCH(r_n_container) - KRATOS_WATCH(ListOfAngles) - KRATOS_WATCH(shape_matrix_x) - KRATOS_WATCH(shape_matrix_y) - KRATOS_WATCH(shape_matrix_z) - } - - IndexType it = i.fetch_add(1) * rVariableList.size(); - - std::vector shape_matrices = {shape_matrix_x, shape_matrix_y, shape_matrix_z}; - - for (std::size_t j = 0; j < rVariableList.size(); ++j) { - if (j >= shape_matrices.size()) { - KRATOS_ERROR << "Unexpected index in rVariableList. Only 3 DoFs (x, y, z) are supported." << std::endl; - } - concurrent_constraints.enqueue(r_clone_constraint.Create(prev_num_mscs + it + j + 1, r_cloud_of_master_dofs, r_slave_dofs[j], shape_matrices[j], constant_vector)); - } - - - }); - - ConstraintContainerType temp_constraints; - ModelPart::MasterSlaveConstraintType::Pointer p_constraint; - - while (concurrent_constraints.try_dequeue(p_constraint)) - temp_constraints.push_back(p_constraint); - - rComputingModelPart.AddMasterSlaveConstraints(temp_constraints.begin(), temp_constraints.end()); - - KRATOS_INFO("AssignRotationalMasterSlaveConstraintsToNodes") << "Build and Assign Rotational Master-Slave Constraints Time: " << build_and_assign_mscs.ElapsedSeconds() << std::endl; - - KRATOS_CATCH(""); -} - -void AssignMasterSlaveConstraintsToNeighboursUtility::ObtainShapeMatrix( - Matrix& shape_matrix_x, - Matrix& shape_matrix_y, - Matrix& shape_matrix_z, - Vector& rN_container, - Vector& ListOfAngles -) -{ - std::vector rotation_x_global; - std::vector rotation_y_global; - std::vector rotation_z_global; - std::vector rotation_x(3); - std::vector rotation_y(3); - std::vector rotation_z(3); - for (int i=0; i < static_cast(rN_container.size()); i++){ - //TODO: Any kind of rotation. x-axis, y-axis, z-axis. Make it a function. - rotation_x[0] = rN_container[i]*cos(ListOfAngles[i]); - rotation_x[1] = -rN_container[i]*sin(ListOfAngles[i]); - rotation_x[2] = rN_container[i]*0.0; - rotation_y[0] = rN_container[i]*sin(ListOfAngles[i]); - rotation_y[1] = rN_container[i]*cos(ListOfAngles[i]); - rotation_y[2] = rN_container[i]*0.0; - rotation_z[0] = rN_container[i]*0.0; - rotation_z[1] = rN_container[i]*0.0; - rotation_z[2] = rN_container[i]*1.0; - // noalias(row(shape_matrix,i)) = aux_vector_x; - rotation_x_global.insert(rotation_x_global.end(),rotation_x.begin(),rotation_x.end()); - rotation_y_global.insert(rotation_y_global.end(),rotation_y.begin(),rotation_y.end()); - rotation_z_global.insert(rotation_z_global.end(),rotation_z.begin(),rotation_z.end()); - } - shape_matrix_x.resize(1, rotation_x_global.size()); - shape_matrix_y.resize(1, rotation_y_global.size()); - shape_matrix_z.resize(1, rotation_z_global.size()); - for (int i=0; i(rotation_x_global.size());i++){ - shape_matrix_x(0,i) = rotation_x_global[i]; - shape_matrix_y(0,i) = rotation_y_global[i]; - shape_matrix_z(0,i) = rotation_z_global[i]; - } -} - -// void AssignMasterSlaveConstraintsToNeighboursUtility::AssignRotationalMasterSlaveConstraintsToNodes( -// NodesContainerType pSlaveNodes, -// double const Radius, -// ModelPart& rComputingModelPart, -// const std::vector>>& rVariableList, -// double const MinNumOfNeighNodes, -// const std::unordered_map>& GhostToOriginalMapping -// ) -// { -// KRATOS_TRY; - -// BuiltinTimer build_and_assign_mscs; - -// thread_local std::vector r_cloud_of_dofs; -// thread_local std::vector r_slave_dofs; -// thread_local Matrix r_cloud_of_nodes_coordinates; -// thread_local array_1d r_slave_coordinates; -// thread_local Vector r_n_container; -// thread_local Vector constant_vector; -// thread_local Matrix shape_matrix; - -// int prev_num_mscs = rComputingModelPart.NumberOfMasterSlaveConstraints(); - -// KRATOS_WARNING_IF("AssignRotationalMasterSlaveConstraintsToNodes", prev_num_mscs > 0) << "Previous Master-Slave Constraints exist in the ModelPart. The new Constraints may interact with the existing ones." << std::endl; - -// auto& p_nodes_array = pSlaveNodes.GetContainer(); - -// const auto& r_clone_constraint = KratosComponents::Get("LinearMasterSlaveConstraint"); - -// using MasterSlaveConstraintQueue = moodycamel::ConcurrentQueue; -// MasterSlaveConstraintQueue concurrent_constraints; - -// std::atomic i(0); - -// block_for_each(p_nodes_array, [&](Node::Pointer& p_slave_node) { - -// double local_radius = Radius; -// ResultNodesContainerType r_cloud_of_nodes(0); -// ResultNodesContainerType r_local_results(mMaxNumberOfNodes); - -// while (r_cloud_of_nodes.size() < MinNumOfNeighNodes) { -// r_cloud_of_nodes.clear(); -// SearchNodesInRadiusForNode(p_slave_node, local_radius, r_cloud_of_nodes, r_local_results); -// local_radius += Radius; -// } - -// GetDofsAndCoordinatesForSlaveNode(p_slave_node, rVariableList, r_slave_dofs, r_slave_coordinates); -// GetDofsAndCoordinatesForCloudOfNodes(r_cloud_of_nodes, rVariableList, r_cloud_of_dofs, r_cloud_of_nodes_coordinates); - -// RBFShapeFunctionsUtility::CalculateShapeFunctions(r_cloud_of_nodes_coordinates, r_slave_coordinates, r_n_container); - -// shape_matrix.resize(1, r_n_container.size()); -// noalias(row(shape_matrix, 0)) = r_n_container; -// constant_vector.resize(r_n_container.size()); - -// // Check if the current slave node is a ghost node and adjust for rotation if necessary -// if (GhostToOriginalMapping.find(p_slave_node->Id()) != GhostToOriginalMapping.end()) { -// auto mapping_data = GhostToOriginalMapping.at(p_slave_node->Id()); -// double rotation_angle = mapping_data.second; -// AdjustConstraintForRotation(rotation_angle, shape_matrix); -// } - -// IndexType it = i.fetch_add(1) * rVariableList.size(); - -// for (std::size_t j = 0; j < rVariableList.size(); ++j) { -// concurrent_constraints.enqueue(r_clone_constraint.Create(prev_num_mscs + it + j + 1, const_cast(r_cloud_of_dofs[j]), r_slave_dofs[j], shape_matrix, constant_vector)); -// } - -// }); - -// ConstraintContainerType temp_constraints; -// ModelPart::MasterSlaveConstraintType::Pointer p_constraint; - -// while (concurrent_constraints.try_dequeue(p_constraint)) -// temp_constraints.push_back(p_constraint); - -// rComputingModelPart.AddMasterSlaveConstraints(temp_constraints.begin(), temp_constraints.end()); - -// KRATOS_INFO("AssignRotationalMasterSlaveConstraintsToNodes") << "Build and Assign Rotational Master-Slave Constraints Time: " << build_and_assign_mscs.ElapsedSeconds() << std::endl; - -// KRATOS_CATCH(""); -// } - -void AssignMasterSlaveConstraintsToNeighboursUtility::AdjustConstraintForRotation(double rotation_angle, Matrix& shape_matrix) -{ - KRATOS_TRY; - - double cos_theta = std::cos(rotation_angle * M_PI / 180.0); // Convert degrees to radians - double sin_theta = std::sin(rotation_angle * M_PI / 180.0); - - for (std::size_t i = 0; i < shape_matrix.size1(); ++i) { - double original_w1 = shape_matrix(i, 0); - double original_w2 = shape_matrix(i, 1); - - shape_matrix(i, 0) = original_w1 * cos_theta - original_w2 * sin_theta; - shape_matrix(i, 1) = original_w1 * sin_theta + original_w2 * cos_theta; - } - - KRATOS_CATCH(""); -} - -void AssignMasterSlaveConstraintsToNeighboursUtility::ExtractAnglesFromMapping( - const ResultNodesContainerType& Results, - const std::unordered_map>& GhostToOriginalMapping, - Vector& ListOfAngles -) -{ - ListOfAngles.resize(Results.size(), false); - for(int i = 0; i < static_cast(Results.size()); i++) - { - auto it = GhostToOriginalMapping.find(Results[i]->Id()); - if(it != GhostToOriginalMapping.end()) - { - ListOfAngles[i] = it->second.second; // Extracting the angle from the mapping - } - else - { - KRATOS_ERROR << "Node ID " << Results[i]->Id() << " not found in GhostToOriginalMapping!" << std::endl; - } - } -} - -} // namespace Kratos. - void AssignMasterSlaveConstraintsToNeighboursUtility::InterpolateVelocityToNodes( NodesContainerType pDestinationNodes, double const Radius, diff --git a/kratos/utilities/assign_master_slave_constraints_to_neighbours_utility.h b/kratos/utilities/assign_master_slave_constraints_to_neighbours_utility.h index 754e74aa4ccd..e4c66cbd225b 100644 --- a/kratos/utilities/assign_master_slave_constraints_to_neighbours_utility.h +++ b/kratos/utilities/assign_master_slave_constraints_to_neighbours_utility.h @@ -137,29 +137,6 @@ class KRATOS_API(KRATOS_CORE) AssignMasterSlaveConstraintsToNeighboursUtility Matrix& rCloudOfNodesCoordinates ); - /** - * @brief Removes duplicate nodes based on their coordinates. - * - * This function is intended to filter out nodes with duplicate coordinates - * to avoid errors when using Radial Basis Functions (RBF) that can't handle - * repetitive coordinates. The function updates the provided CloudOfNodesArray - * to only contain unique nodes and also returns a matrix of their coordinates. - * - * @param CloudOfNodesArray A reference to the container of nodes. This will be updated to only contain unique nodes. - * @param rCloudOfNodesCoordinates A reference to a matrix that will be filled with the coordinates of the unique nodes. - */ - void FilterUniqueNodesForRBF( - ResultNodesContainerType& CloudOfNodesArray, - Matrix& rCloudOfNodesCoordinates - ); - - void GetDofsAndCoordinatesForCloudOfNodesFlattened( - const ResultNodesContainerType& CloudOfNodesArray, - const std::vector>>& rVariableList, - DofPointerVectorType& rCloudOfDofs, - Matrix& rCloudOfNodesCoordinates - ); - /** * @brief Assign Master-Slave Constraints to a set of Nodes. * @details Assign Matser-Slave Constraints to a set of Nodes given a radius of influence @@ -178,57 +155,12 @@ class KRATOS_API(KRATOS_CORE) AssignMasterSlaveConstraintsToNeighboursUtility double const MinNumOfNeighNodes ); - /** - * @brief Assign Rotational Master-Slave Constraints to a set of Nodes. - * @details This function assigns Master-Slave Constraints to a set of nodes considering rotational effects. - * It takes into account the rotation of the nodes and adjusts the constraints accordingly. The function - * uses MLS or RBF shape functions within a given radius of influence to determine the constraints. - * Additionally, it uses a mapping between ghost nodes and their original counterparts to account for the rotation. - * @param pSlaveNodes Nodes to which MasterSlaveConstraints are assigned. - * @param Radius Search radius for neighboring nodes. - * @param rComputingModelPart Model Part to which MasterSlaveConstraints are applied. - * @param rVariableList List of DOFs to assign the MasterSlaveConstraints. - * @param MinNumOfNeighNodes Minimum number of neighboring nodes required for the constraint. - * @param GhostToOriginalMapping Mapping between ghost nodes and their original counterparts, including the rotation angle. - */ - void AssignRotationalMasterSlaveConstraintsToNodes( - NodesContainerType pSlaveNodes, + void InterpolateVelocityToNodes( + NodesContainerType pDestinationNodes, double const Radius, - ModelPart& rComputingModelPart, const std::vector>>& rVariableList, - double const MinNumOfNeighNodes, - const std::unordered_map>& GhostToOriginalMapping - ); - /** - * @brief Adjusts the Master-Slave Constraint for rotational effects. - * @details This function modifies the shape functions matrix (weights) of the Master-Slave Constraint - * to account for the rotation of the nodes. Given a rotation angle, it applies the necessary - * trigonometric transformations to the shape functions to ensure that the constraints are correctly - * adjusted for the rotation. This is crucial when dealing with models that have rotational dynamics - * or when considering ghost nodes that represent rotated versions of the original nodes. - * @param rotation_angle The angle (in degrees) by which the node has been rotated. - * @param shape_matrix The shape functions matrix that needs adjustment for rotation. - */ - void AdjustConstraintForRotation( - double rotation_angle, - Matrix& shape_matrix - ); - - void ExtractAnglesFromMapping( - const ResultNodesContainerType& Results, - const std::unordered_map>& GhostToOriginalMapping, - Vector& ListOfAngles - ); - - void ObtainShapeMatrix( - Matrix& shape_matrix_x, - Matrix& shape_matrix_y, - Matrix& shape_matrix_z, - Vector& rN_container, - Vector& ListOfAngles - ); - - + double const MinNumOfNeighNodes + ); ///@} ///@name Input and output