From e0b72ec922f72804d4abecd6e74abe7b6db91c35 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Sat, 20 Dec 2025 00:30:07 +0100 Subject: [PATCH 001/116] skip some tests if MeshMovingApplication is not found. --- .../tests/control/shape/test_vm_shape_control.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/OptimizationApplication/tests/control/shape/test_vm_shape_control.py b/applications/OptimizationApplication/tests/control/shape/test_vm_shape_control.py index 093a400f046d..f851c7c04900 100644 --- a/applications/OptimizationApplication/tests/control/shape/test_vm_shape_control.py +++ b/applications/OptimizationApplication/tests/control/shape/test_vm_shape_control.py @@ -63,7 +63,7 @@ def tearDownClass(cls): with kratos_unittest.WorkFolderScope(".", __file__): DeleteFileIfExisting(f"{cls.GetMdpaFileName()}.time") -@kratos_unittest.skipIfApplicationsNotAvailable("StructuralMechanicsApplication") +@kratos_unittest.skipIfApplicationsNotAvailable("StructuralMechanicsApplication", "MeshMovingApplication") class TestVMShapeControlShell(TestVMShapeControlBase, kratos_unittest.TestCase): @classmethod def GetImplicitControlParameters(self) -> Kratos.Parameters: @@ -145,7 +145,7 @@ def test_UpdateExplicit(self): self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(explicit_control_field), 3.633180424916991, 10) self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(explicit_shape_field), 22.013379276492945, 10) -@kratos_unittest.skipIfApplicationsNotAvailable("StructuralMechanicsApplication") +@kratos_unittest.skipIfApplicationsNotAvailable("StructuralMechanicsApplication", "MeshMovingApplication") class TestVMShapeControlSolid(TestVMShapeControlBase, kratos_unittest.TestCase): @classmethod def GetImplicitControlParameters(self) -> Kratos.Parameters: From b9f841fa20dc29b0ebad7e5dd8276ca6e7d520da Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Sat, 20 Dec 2025 01:09:03 +0100 Subject: [PATCH 002/116] add properties variable TA --- .../properties_variable_tensor_adaptor.cpp | 216 ++++++++++++++++++ .../properties_variable_tensor_adaptor.h | 139 +++++++++++ 2 files changed, 355 insertions(+) create mode 100644 applications/OptimizationApplication/custom_utilities/properties_variable_tensor_adaptor.cpp create mode 100644 applications/OptimizationApplication/custom_utilities/properties_variable_tensor_adaptor.h diff --git a/applications/OptimizationApplication/custom_utilities/properties_variable_tensor_adaptor.cpp b/applications/OptimizationApplication/custom_utilities/properties_variable_tensor_adaptor.cpp new file mode 100644 index 000000000000..29ad3550acb7 --- /dev/null +++ b/applications/OptimizationApplication/custom_utilities/properties_variable_tensor_adaptor.cpp @@ -0,0 +1,216 @@ +// | / | +// ' / __| _` | __| _ \ __| +// . \ | ( | | ( |\__ ` +// _|\_\_| \__,_|\__|\___/ ____/ +// Multi-Physics +// +// License: BSD License +// Kratos default license: kratos/license.txt +// +// Main authors: Suneth Warnakulasuriya +// + +// System includes +#include +#include + +// External includes + +// Project includes + +// Include base h +#include "properties_variable_tensor_adaptor.h" + +namespace Kratos { + +template +PropertiesVariableTensorAdaptor::PropertiesVariableTensorAdaptor( + TContainerPointerType pContainer, + VariablePointerType pVariable) + : mpVariable(pVariable) +{ + this->mpContainer = pContainer; + + std::visit([this, pContainer](auto pVariable) { + this->mpStorage = Kratos::make_shared( + TensorAdaptorUtils::GetTensorShape( + *pContainer, *pVariable, + [pVariable](auto& rValue, const auto& rEntity) { + rValue = rEntity.GetProperties().GetValue(*pVariable); + })); + }, mpVariable); +} + +template +PropertiesVariableTensorAdaptor::PropertiesVariableTensorAdaptor( + TContainerPointerType pContainer, + VariablePointerType pVariable, + const std::vector& rDataShape) + : mpVariable(pVariable) +{ + this->mpContainer = pContainer; + + std::visit([&rDataShape, this, pContainer](auto pVariable) { + this->mpStorage = Kratos::make_shared( + TensorAdaptorUtils::GetTensorShape( + *pContainer, *pVariable, rDataShape.data(), + rDataShape.data() + rDataShape.size())); + }, mpVariable); +} + +PropertiesVariableTensorAdaptor::PropertiesVariableTensorAdaptor( + const TensorAdaptor& rOther, + VariablePointerType pVariable, + const bool Copy) + : BaseType(rOther, Copy), + mpVariable(pVariable) +{ + KRATOS_TRY + + if (!HoldsAlternative::Evaluate(this->GetContainer())) { + KRATOS_ERROR << "PropertiesVariableTensorAdaptor can only be used with tensor data having condition and element containers " + << "[ tensor adaptor = " << rOther << " ].\n"; + } + + // now check whether the given storage is compatible with the variable. + std::visit([this, &rOther](auto pVariable) { + using data_type = typename BareType::Type; + const auto& r_data_shape = this->DataShape(); + KRATOS_ERROR_IF_NOT(DataTypeTraits::IsValidShape(r_data_shape.data().begin(), r_data_shape.data().begin() + r_data_shape.size())) + << "The data storage within the tensor data is not compatible with the " << pVariable->Name() + << " [ origin data shape = " << rOther.DataShape() << ", tensor adaptor = " << *this << " ].\n"; + + }, mpVariable); + + KRATOS_CATCH(""); +} + +void PropertiesVariableTensorAdaptor::Check() const +{ + KRATOS_TRY + + BaseType::Check(); + + std::visit([](auto pContainer, auto pVariable) { + using container_type = BareType; + + if constexpr(IsInList) { + + block_for_each(*pContainer, [&pVariable](const auto& rEntity) { + KRATOS_ERROR_IF_NOT(rEntity.GetProperties().Has(*pVariable)) + << "The entity with id = " << rEntity.Id() << " does not have the variable " << pVariable->Name() << ".\n"; + }); + + // here we have to check for the uniqueness of the variable as well, because + // otherwise, when StoreData method is called, it can lead to race conditions. + using variable_type = BareType; + + std::vector memory_locations(pContainer->size()); + IndexPartition(pContainer->size()).for_each([&pVariable, &memory_locations, &pContainer](const auto Index) { + memory_locations[Index] = &(pContainer->begin() + Index)->GetProperties().GetValue(*pVariable); + }); + + std::set unique_memory_locations(memory_locations.begin(), memory_locations.end()); + KRATOS_ERROR_IF_NOT(unique_memory_locations.size() == memory_locations.size()) + << "The container's entities' properties does not have unique memory locations assigned for variable " + << pVariable->Name() << " ."; + } + }, this->GetContainer(), mpVariable); + + KRATOS_CATCH(""); +} + +void PropertiesVariableTensorAdaptor::CollectData() +{ + std::visit([this](auto pContainer, auto pVariable) { + using container_type = BareType; + + if constexpr(IsInList) { + + using variable_type = BareType; + using data_type = typename variable_type::Type; + + const auto& r_tensor_shape = this->Shape(); + + KRATOS_ERROR_IF_NOT(r_tensor_shape[0] == pContainer->size()) + << "Underlying container of the tensor data has changed size [ tensor data = " + << this->Info() << ", container size = " << pContainer->size() << " ].\n"; + + ContainerIOUtils::CopyToContiguousArray( + *pContainer, this->ViewData(), r_tensor_shape.data().begin(), + r_tensor_shape.data().begin() + r_tensor_shape.size(), + [pVariable](auto& rValue, const auto& rEntity) { + rValue = rEntity.GetProperties().GetValue(*pVariable); + }); + } + }, this->GetContainer(), mpVariable); +} + +void PropertiesVariableTensorAdaptor::StoreData() +{ + std::visit([this](auto pContainer, auto pVariable) { + using container_type = BareType; + + if constexpr(IsInList) { + + using variable_type = BareType; + using data_type = typename variable_type::Type; + + const auto& r_tensor_shape = this->Shape(); + + KRATOS_ERROR_IF_NOT(r_tensor_shape[0] == pContainer->size()) + << "Underlying container of the tensor data has changed size [ tensor data = " + << this->Info() << ", container size = " << pContainer->size() << " ].\n"; + + if constexpr(DataTypeTraits::IsDynamic) { + // this zero value may be different from the Variable::Zero() + // in the case where the variable type is Variable or Variable. + // Because, in these dynamic data type variables, Variable::Zero will create + // a zero sized vector or matrix, which is useless in the StoreData method. + // The following method creates correctly sized zero Vector or Matrix + // accordingly to be assigned to the entities, if they don't have the specified + // variable in their DataValueContainer. + const auto& zero = TensorAdaptorUtils::GetZeroValue(*pVariable, this->DataShape()); + + ContainerIOUtils::CopyFromContiguousDataArray( + *pContainer, this->ViewData(), r_tensor_shape.data().begin(), + r_tensor_shape.data().begin() + r_tensor_shape.size(), + [pVariable, &zero](auto& rEntity) -> auto& { + return rEntity.GetProperties().Emplace(*pVariable, zero); + }); + } else { + ContainerIOUtils::CopyFromContiguousDataArray( + *pContainer, this->ViewData(), r_tensor_shape.data().begin(), + r_tensor_shape.data().begin() + r_tensor_shape.size(), + [pVariable](auto& rEntity) -> auto& { + return rEntity.GetProperties().Emplace(*pVariable); + }); + } + } + }, this->GetContainer(), mpVariable); +} + +std::string PropertiesVariableTensorAdaptor::Info() const +{ + std::stringstream info; + info << "PropertiesVariableTensorAdaptor:"; + std::visit([&info](auto pVariable) { + info << " Variable = " << pVariable->Name(); + }, this->mpVariable); + info << ", " << BaseType::Info(); + return info.str(); +} + +template KRATOS_API(OPTIMIZATION_APPLICATION) PropertiesVariableTensorAdaptor::PropertiesVariableTensorAdaptor(ModelPart::ConditionsContainerType::Pointer, VariablePointerType); +template KRATOS_API(OPTIMIZATION_APPLICATION) PropertiesVariableTensorAdaptor::PropertiesVariableTensorAdaptor(ModelPart::ConditionsContainerType::Pointer, VariablePointerType, const std::vector&); +template KRATOS_API(OPTIMIZATION_APPLICATION) PropertiesVariableTensorAdaptor::PropertiesVariableTensorAdaptor(ModelPart::ElementsContainerType::Pointer, VariablePointerType); +template KRATOS_API(OPTIMIZATION_APPLICATION) PropertiesVariableTensorAdaptor::PropertiesVariableTensorAdaptor(ModelPart::ElementsContainerType::Pointer, VariablePointerType, const std::vector&); + +} // namespace Kratos \ No newline at end of file diff --git a/applications/OptimizationApplication/custom_utilities/properties_variable_tensor_adaptor.h b/applications/OptimizationApplication/custom_utilities/properties_variable_tensor_adaptor.h new file mode 100644 index 000000000000..414453afc5ab --- /dev/null +++ b/applications/OptimizationApplication/custom_utilities/properties_variable_tensor_adaptor.h @@ -0,0 +1,139 @@ +// | / | +// ' / __| _` | __| _ \ __| +// . \ | ( | | ( |\__ ` +// _|\_\_| \__,_|\__|\___/ ____/ +// Multi-Physics +// +// License: BSD License +// Kratos default license: kratos/license.txt +// +// Main authors: Suneth Warnakulasuriya +// + +#pragma once + +// System includes +#include + +// External includes + +// Project includes +#include "tensor_adaptors/tensor_adaptor.h" +#include "tensor_adaptors/tensor_adaptor_utils.h" + +namespace Kratos { + +///@name Kratos Classes +///@{ + +/** + * @class PropertiesVariableTensorAdaptor + * @ingroup TensorAdaptors + * @brief Adaptor class for handling values represented as variables in Kratos entities' properties. + * + * @details This class provides an interface to collect and store tensor data associated with Kratos entities' property variables + * specified by @p pVariable in the Properties. It extends TensorAdaptor and allows for flexible data management, + * including initialization, data collection, and storage operations. + * + * @section PropertiesVariableTensorAdaptor_supported_container Supported container types + * - @ref ModelPart::ConditionsContainerType + * - @ref ModelPart::ElementsContainerType + * + * @section PropertiesVariableTensorAdaptor_usage Usage + * - Use @ref Check to verify that the variable exists and they are holding unique memory locations in the entities' properties before collecting/storing data. + * - Use @ref CollectData to fill internal data from Kratos data structures entities' properties. + * - Use @ref StoreData to write internal data back to the container's entities' properties, adding the variable if necessary. + * + * @author Suneth Warnakulasuriya + * @see @ref TensorAdaptor Base class. + * @see @ref DataValueContainer::GetValue Variable value retrieval/update method. + * @see @ref DataValueContainer::SetValue Variable value set method. + */ +class KRATOS_API(OPTIMIZATION_APPLICATION) PropertiesVariableTensorAdaptor: public TensorAdaptor { +public: + + ///@name Type definitions + ///@{ + + KRATOS_CLASS_POINTER_DEFINITION(PropertiesVariableTensorAdaptor); + + using BaseType = TensorAdaptor; + + using VariablePointerType = TensorAdaptorUtils::VariablePointerType; + + ///@} + ///@name Life cycle + ///@{ + + template + PropertiesVariableTensorAdaptor( + TContainerPointerType pContainer, + VariablePointerType pVariable); + + template + PropertiesVariableTensorAdaptor( + TContainerPointerType pContainer, + VariablePointerType pVariable, + const std::vector& rDataShape); + + PropertiesVariableTensorAdaptor( + const TensorAdaptor& rOther, + VariablePointerType pVariable, + const bool Copy = true); + + // Destructor + ~PropertiesVariableTensorAdaptor() override = default; + + ///@} + ///@name Public operations + ///@{ + + /** + * @brief Execution of this check is only required if this PropertiesVariableTensorAdaptor + * will be used to call the @ref CollectData method. If it is only required to be called + * with the @ref StoreData, then please do not execute this @ref Check. Because + * then this Check will disallow storing data by throwing an error, when the entities do not have the variables + * already defined. + * @see StoreData + */ + void Check() const override; + + /** + * @brief Fill the internal data from Kratos data structures's properties + * @details This will fill the internal data from Kratos data structures's properties. It is advised to call + * at least once the Check method to ensure there won't be any errors if the + * variable is not present in the entities' properties. This will return Variable::Zero() + * values for all the entities when collecting if the variable is not set before. + */ + void CollectData() override; + + /** + * @brief Store internal data to the given container's properties. + * @details This method is designed to store data even if the variable is not already available in the + * entities' properties. If it is not present in the entities' properties, then a correctly shaped zero valued value + * will be set and then their relevant components will be overwritten by this method. + * @warning Do not call @ref Check if you intend to use PropertiesVariableTensorAdaptor to add the variable + * to the entities, and avoid unnecessarily initializing dummy values. + * @warning If the entities' properties are not unique for each entity, this will result in a race condition. + */ + void StoreData() override; + + ///@} + ///@name Input and output + ///@{ + + std::string Info() const override; + + ///@} + +private: + ///@name Private member variables + ///@{ + + VariablePointerType mpVariable; + + ///@} +}; + +/// @} +} // namespace Kratos \ No newline at end of file From b6727b2c5e7d4bd640f65f66e729a63f0e10e8ab Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Sat, 20 Dec 2025 01:09:20 +0100 Subject: [PATCH 003/116] expose to python --- .../custom_python/add_custom_utilities_to_python.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/applications/OptimizationApplication/custom_python/add_custom_utilities_to_python.cpp b/applications/OptimizationApplication/custom_python/add_custom_utilities_to_python.cpp index a775dcb27651..c60275f329cb 100644 --- a/applications/OptimizationApplication/custom_python/add_custom_utilities_to_python.cpp +++ b/applications/OptimizationApplication/custom_python/add_custom_utilities_to_python.cpp @@ -29,6 +29,7 @@ #include "custom_utilities/implicit_filter_utils.h" #include "custom_utilities/optimization_utils.h" #include "custom_utilities/properties_variable_expression_io.h" +#include "custom_utilities/properties_variable_tensor_adaptor.h" // Include base h #include "add_custom_response_utilities_to_python.h" @@ -379,6 +380,14 @@ void AddCustomUtilitiesToPython(pybind11::module& m) py::arg("variable"), py::arg("data_location")) ; + + py::class_(m, "PropertiesVariableTensorAdaptor") + .def(py::init(), py::arg("tensor_adaptor"), py::arg("variable"), py::arg("copy") = true) + .def(py::init(), py::arg("container"), py::arg("variable")) + .def(py::init&>(), py::arg("container"), py::arg("variable"), py::arg("data_shape")) + .def(py::init(), py::arg("container"), py::arg("variable")) + .def(py::init&>(), py::arg("container"), py::arg("variable"), py::arg("data_shape")) + ; } } // namespace Python. From e38e3d5a5f0e3fd77156c48101f5b68a1701c59d Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Sat, 20 Dec 2025 20:56:33 +0100 Subject: [PATCH 004/116] minor comment change in PropertiesVarTA --- .../custom_utilities/properties_variable_tensor_adaptor.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/applications/OptimizationApplication/custom_utilities/properties_variable_tensor_adaptor.h b/applications/OptimizationApplication/custom_utilities/properties_variable_tensor_adaptor.h index 414453afc5ab..fa62bd875340 100644 --- a/applications/OptimizationApplication/custom_utilities/properties_variable_tensor_adaptor.h +++ b/applications/OptimizationApplication/custom_utilities/properties_variable_tensor_adaptor.h @@ -112,8 +112,7 @@ class KRATOS_API(OPTIMIZATION_APPLICATION) PropertiesVariableTensorAdaptor: publ * @details This method is designed to store data even if the variable is not already available in the * entities' properties. If it is not present in the entities' properties, then a correctly shaped zero valued value * will be set and then their relevant components will be overwritten by this method. - * @warning Do not call @ref Check if you intend to use PropertiesVariableTensorAdaptor to add the variable - * to the entities, and avoid unnecessarily initializing dummy values. + * * @warning If the entities' properties are not unique for each entity, this will result in a race condition. */ void StoreData() override; From 1c8e7efc86106ea6d7df5586e886aa87a4f95bfb Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Sat, 20 Dec 2025 20:56:50 +0100 Subject: [PATCH 005/116] add unit test to PropertiesVarTA --- .../tests/test_container_expression.py | 125 ++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/applications/OptimizationApplication/tests/test_container_expression.py b/applications/OptimizationApplication/tests/test_container_expression.py index c5ebcbebbd27..411eeb1c5d98 100644 --- a/applications/OptimizationApplication/tests/test_container_expression.py +++ b/applications/OptimizationApplication/tests/test_container_expression.py @@ -8,6 +8,131 @@ # Import KratosUnittest import KratosMultiphysics.KratosUnittest as kratos_unittest +class TestPropertiesVariableTensorAdaptor(kratos_unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.model = Kratos.Model() + cls.model_part = cls.model.CreateModelPart("test") + cls.model_part.AddNodalSolutionStepVariable(Kratos.DENSITY) + cls.model_part.AddNodalSolutionStepVariable(Kratos.PRESSURE) + cls.model_part.AddNodalSolutionStepVariable(Kratos.ACCELERATION) + cls.model_part.AddNodalSolutionStepVariable(Kratos.VELOCITY) + with kratos_unittest.WorkFolderScope(".", __file__, True): + ReadModelPart("model_part_utils_test/quads", cls.model_part) + + for node in cls.model_part.Nodes: + id = node.Id + node.SetSolutionStepValue(Kratos.VELOCITY, Kratos.Array3([id+3, id+4, id+5])) + node.SetSolutionStepValue(Kratos.PRESSURE, id+3) + node.SetValue(Kratos.PRESSURE, id+3) + node.SetValue(Kratos.VELOCITY, Kratos.Array3([id+3, id+4, id+5])) + + KratosOA.OptimizationUtils.CreateEntitySpecificPropertiesForContainer(cls.model_part, cls.model_part.Conditions, True) + for condition in cls.model_part.Conditions: + id = condition.Id + condition.Properties[Kratos.PRESSURE] = id+400 + condition.Properties[Kratos.VELOCITY] = Kratos.Array3([id+500, id+600, id+700]) + condition.SetValue(Kratos.PRESSURE, id+4) + condition.SetValue(Kratos.VELOCITY, Kratos.Array3([id+5, id+6, id+7])) + + KratosOA.OptimizationUtils.CreateEntitySpecificPropertiesForContainer(cls.model_part, cls.model_part.Elements, True) + for element in cls.model_part.Elements: + id = element.Id + element.Properties[Kratos.PRESSURE] = id+500 + element.Properties[Kratos.VELOCITY] = Kratos.Array3([id+600, id+700, id+800]) + element.SetValue(Kratos.PRESSURE, id+5) + element.SetValue(Kratos.VELOCITY, Kratos.Array3([id+6, id+7, id+8])) + + def test_Check(self): + model = Kratos.Model() + model_part = model.CreateModelPart("test") + model_part.AddNodalSolutionStepVariable(Kratos.DENSITY) + model_part.AddNodalSolutionStepVariable(Kratos.PRESSURE) + model_part.AddNodalSolutionStepVariable(Kratos.ACCELERATION) + model_part.AddNodalSolutionStepVariable(Kratos.VELOCITY) + with kratos_unittest.WorkFolderScope(".", __file__, True): + ReadModelPart("model_part_utils_test/quads", model_part) + + ta = KratosOA.PropertiesVariableTensorAdaptor(model_part.Elements, Kratos.PRESSURE) + with self.assertRaises(RuntimeError): + ta.Check() + + model_part.GetProperties(1)[Kratos.PRESSURE] = 1.0 + with self.assertRaises(RuntimeError): + ta.Check() + + def test_ElementPropertiesScalar(self): + ta = KratosOA.PropertiesVariableTensorAdaptor(self.model_part.Elements, Kratos.PRESSURE) + ta.Check() + ta.CollectData() + + original_ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(ta) + + ta.data *= 2.1 + + for i, element in enumerate(self.model_part.Elements): + self.assertEqual(ta.data[i], element.Properties[Kratos.PRESSURE] * 2.1) + + ta.data *= 4.3 + ta.StoreData() + + for i, element in enumerate(self.model_part.Elements): + self.assertEqual(element.Properties[Kratos.PRESSURE], original_ta.data[i] * 2.1 * 4.3) + + def test_ElementPropertiesVector(self): + ta = KratosOA.PropertiesVariableTensorAdaptor(self.model_part.Elements, Kratos.VELOCITY) + ta.Check() + ta.CollectData() + + original_ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(ta) + + ta.data *= 2.1 + + for i, element in enumerate(self.model_part.Elements): + self.assertVectorAlmostEqual(ta.data[i], element.Properties[Kratos.VELOCITY] * 2.1) + + ta.data *= 4.3 + ta.StoreData() + + for i, element in enumerate(self.model_part.Elements): + self.assertVectorAlmostEqual(element.Properties[Kratos.VELOCITY], original_ta.data[i] * 2.1 * 4.3) + + def test_ConditionPropertiesScalar(self): + ta = KratosOA.PropertiesVariableTensorAdaptor(self.model_part.Conditions, Kratos.PRESSURE) + ta.Check() + ta.CollectData() + + original_ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(ta) + + ta.data *= 2.1 + + for i, condition in enumerate(self.model_part.Conditions): + self.assertEqual(ta.data[i], condition.Properties[Kratos.PRESSURE] * 2.1) + + ta.data *= 4.3 + ta.StoreData() + + for i, condition in enumerate(self.model_part.Conditions): + self.assertEqual(condition.Properties[Kratos.PRESSURE], original_ta.data[i] * 2.1 * 4.3) + + def test_ConditionPropertiesVector(self): + ta = KratosOA.PropertiesVariableTensorAdaptor(self.model_part.Conditions, Kratos.VELOCITY) + ta.Check() + ta.CollectData() + + original_ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(ta) + + ta.data *= 2.1 + + for i, condition in enumerate(self.model_part.Conditions): + self.assertVectorAlmostEqual(ta.data[i], condition.Properties[Kratos.VELOCITY] * 2.1) + + ta.data *= 4.3 + ta.StoreData() + + for i, condition in enumerate(self.model_part.Conditions): + self.assertVectorAlmostEqual(condition.Properties[Kratos.VELOCITY], original_ta.data[i] * 2.1 * 4.3) + class TestContainerExpression(ABC): @classmethod def CreateEntities(cls): From fc6c0767a16200a11151841533cb6d2011ec6fda Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Mon, 22 Dec 2025 22:26:48 +0100 Subject: [PATCH 006/116] update mass resp utils to TA --- .../response/mass_response_utils.cpp | 54 ++++++++----------- .../response/mass_response_utils.h | 6 +-- 2 files changed, 25 insertions(+), 35 deletions(-) diff --git a/applications/OptimizationApplication/custom_utilities/response/mass_response_utils.cpp b/applications/OptimizationApplication/custom_utilities/response/mass_response_utils.cpp index 821447b201aa..6c6f8eefeb1e 100644 --- a/applications/OptimizationApplication/custom_utilities/response/mass_response_utils.cpp +++ b/applications/OptimizationApplication/custom_utilities/response/mass_response_utils.cpp @@ -17,7 +17,7 @@ #include // Project includes -#include "expression/variable_expression_io.h" +#include "tensor_adaptors/variable_tensor_adaptor.h" #include "includes/define.h" #include "includes/variables.h" #include "utilities/element_size_calculator.h" @@ -27,7 +27,7 @@ // Application includes #include "custom_utilities/optimization_utils.h" -#include "custom_utilities/properties_variable_expression_io.h" +#include "custom_utilities/properties_variable_tensor_adaptor.h" #include "optimization_application_variables.h" // Include base h @@ -120,7 +120,7 @@ void MassResponseUtils::CalculateGradient( const PhysicalFieldVariableTypes& rPhysicalVariable, ModelPart& rGradientRequiredModelPart, ModelPart& rGradientComputedModelPart, - std::vector& rListOfContainerExpressions, + CombinedTensorAdaptor& rCombinedTensorAdaptor, const double PerturbationSize) { KRATOS_TRY @@ -161,36 +161,28 @@ void MassResponseUtils::CalculateGradient( } // now fill the container expressions - for (auto& p_container_expression : rListOfContainerExpressions) { - std::visit([pVariable](auto& pContainerExpression){ - using container_type = std::decay_t; - - if (*pVariable == SHAPE) { - if constexpr(std::is_same_v>) { - VariableExpressionIO::Read(*pContainerExpression, &SHAPE_SENSITIVITY, false); - } else { - KRATOS_ERROR << "Requesting sensitivity w.r.t. " - "SHAPE for a Container expression " - "which is not a NodalExpression. [ " - "Requested container expression = " - << *pContainerExpression << " ].\n"; - } + for (auto p_tensor_adaptor : rCombinedTensorAdaptor.GetTensorAdaptors()) { + std::visit([&p_tensor_adaptor, &pVariable](const auto& pContainer) { + using container_type = BareType; + + if constexpr(std::is_same_v) { + KRATOS_ERROR_IF_NOT(*pVariable == SHAPE) + << "Sensitivity w.r.t. " << pVariable->Name() + << " can be computed on an element tensor adaptor only. " + << "Requested tensor adaptor = " + << *p_tensor_adaptor << " ].\n"; + VariableTensorAdaptor(*p_tensor_adaptor, &SHAPE_SENSITIVITY, false).CollectData(); } else { - if constexpr(std::is_same_v>) { - const auto& sensitivity_variable = KratosComponents>::Get(pVariable->Name() + "_SENSITIVITY"); - PropertiesVariableExpressionIO::Read(*pContainerExpression, &sensitivity_variable); - } else { - KRATOS_ERROR << "Requesting sensitivity w.r.t. " - << pVariable->Name() - << " for a Container expression " - "which is not an ElementExpression. [ " - "Requested container expression = " - << *pContainerExpression << " ].\n"; - } + KRATOS_ERROR_IF(*pVariable == SHAPE) + << "Sensitivity w.r.t. " << pVariable->Name() + << " can be computed on a nodal tensor adaptor only. " + << "Requested tensor adaptor = " + << *p_tensor_adaptor << " ].\n"; + + const auto& sensitivity_variable = KratosComponents>::Get(pVariable->Name() + "_SENSITIVITY"); + PropertiesVariableTensorAdaptor(*p_tensor_adaptor, &sensitivity_variable, false).CollectData(); } - - - }, p_container_expression); + }, p_tensor_adaptor->GetContainer()); } }, rPhysicalVariable); diff --git a/applications/OptimizationApplication/custom_utilities/response/mass_response_utils.h b/applications/OptimizationApplication/custom_utilities/response/mass_response_utils.h index b2d92625087a..9866a12a6845 100644 --- a/applications/OptimizationApplication/custom_utilities/response/mass_response_utils.h +++ b/applications/OptimizationApplication/custom_utilities/response/mass_response_utils.h @@ -20,7 +20,7 @@ // Project includes #include "includes/define.h" #include "includes/model_part.h" -#include "expression/container_expression.h" +#include "tensor_adaptors/combined_tensor_adaptor.h" // Application includes @@ -42,8 +42,6 @@ class KRATOS_API(OPTIMIZATION_APPLICATION) MassResponseUtils using PhysicalFieldVariableTypes = std::variant*, const Variable>*>; - using ContainerExpressionType = std::variant::Pointer, ContainerExpression::Pointer, ContainerExpression::Pointer>; - ///@} ///@name Static operations ///@{ @@ -56,7 +54,7 @@ class KRATOS_API(OPTIMIZATION_APPLICATION) MassResponseUtils const PhysicalFieldVariableTypes& rPhysicalVariable, ModelPart& rGradientRequiredModelPart, ModelPart& rGradientComputedModelPart, - std::vector& rListOfContainerExpressions, + CombinedTensorAdaptor& rCombinedTensorAdaptor, const double PerturbationSize); ///@} From f2389764a8b2929d5699262ebdcf39517f208acd Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Mon, 22 Dec 2025 22:27:04 +0100 Subject: [PATCH 007/116] update linear strain energy resp utils to TA --- .../linear_strain_energy_response_utils.cpp | 54 ++++++++----------- .../linear_strain_energy_response_utils.h | 6 +-- 2 files changed, 25 insertions(+), 35 deletions(-) diff --git a/applications/OptimizationApplication/custom_utilities/response/linear_strain_energy_response_utils.cpp b/applications/OptimizationApplication/custom_utilities/response/linear_strain_energy_response_utils.cpp index 8a876455f59c..84b9862f720e 100644 --- a/applications/OptimizationApplication/custom_utilities/response/linear_strain_energy_response_utils.cpp +++ b/applications/OptimizationApplication/custom_utilities/response/linear_strain_energy_response_utils.cpp @@ -27,8 +27,8 @@ #include "utilities/model_part_operation_utilities.h" // Application includes -#include "expression/variable_expression_io.h" -#include "custom_utilities/properties_variable_expression_io.h" +#include "tensor_adaptors/variable_tensor_adaptor.h" +#include "custom_utilities/properties_variable_tensor_adaptor.h" #include "optimization_application_variables.h" // Include base h @@ -85,7 +85,7 @@ void LinearStrainEnergyResponseUtils::CalculateGradient( const PhysicalFieldVariableTypes& rPhysicalVariable, ModelPart& rGradientRequiredModelPart, ModelPart& rGradientComputedModelPart, - std::vector& rListOfContainerExpressions, + CombinedTensorAdaptor& rCombinedTensorAdaptor, const double PerturbationSize) { KRATOS_TRY @@ -114,36 +114,28 @@ void LinearStrainEnergyResponseUtils::CalculateGradient( } // now fill the container expressions - for (auto& p_container_expression : rListOfContainerExpressions) { - std::visit([pVariable](auto& pContainerExpression){ - using container_type = std::decay_t; - - if (*pVariable == SHAPE) { - if constexpr(std::is_same_v>) { - VariableExpressionIO::Read(*pContainerExpression, &SHAPE_SENSITIVITY, false); - } else { - KRATOS_ERROR << "Requesting sensitivity w.r.t. " - "SHAPE for a Container expression " - "which is not a NodalExpression. [ " - "Requested container expression = " - << *pContainerExpression << " ].\n"; - } + for (auto p_tensor_adaptor : rCombinedTensorAdaptor.GetTensorAdaptors()) { + std::visit([&p_tensor_adaptor, &pVariable](const auto& pContainer) { + using container_type = BareType; + + if constexpr(std::is_same_v) { + KRATOS_ERROR_IF_NOT(*pVariable == SHAPE) + << "Sensitivity w.r.t. " << pVariable->Name() + << " can be computed on an element tensor adaptor only. " + << "Requested tensor adaptor = " + << *p_tensor_adaptor << " ].\n"; + VariableTensorAdaptor(*p_tensor_adaptor, &SHAPE_SENSITIVITY, false).CollectData(); } else { - if constexpr(std::is_same_v>) { - const auto& sensitivity_variable = KratosComponents>::Get(pVariable->Name() + "_SENSITIVITY"); - PropertiesVariableExpressionIO::Read(*pContainerExpression, &sensitivity_variable); - } else { - KRATOS_ERROR << "Requesting sensitivity w.r.t. " - << pVariable->Name() - << " for a Container expression " - "which is not an ElementExpression. [ " - "Requested container expression = " - << *pContainerExpression << " ].\n"; - } + KRATOS_ERROR_IF(*pVariable == SHAPE) + << "Sensitivity w.r.t. " << pVariable->Name() + << " can be computed on a nodal tensor adaptor only. " + << "Requested tensor adaptor = " + << *p_tensor_adaptor << " ].\n"; + + const auto& sensitivity_variable = KratosComponents>::Get(pVariable->Name() + "_SENSITIVITY"); + PropertiesVariableTensorAdaptor(*p_tensor_adaptor, &sensitivity_variable, false).CollectData(); } - - - }, p_container_expression); + }, p_tensor_adaptor->GetContainer()); } }, rPhysicalVariable); diff --git a/applications/OptimizationApplication/custom_utilities/response/linear_strain_energy_response_utils.h b/applications/OptimizationApplication/custom_utilities/response/linear_strain_energy_response_utils.h index 68b563196444..e5a0ff4e0be5 100644 --- a/applications/OptimizationApplication/custom_utilities/response/linear_strain_energy_response_utils.h +++ b/applications/OptimizationApplication/custom_utilities/response/linear_strain_energy_response_utils.h @@ -20,7 +20,7 @@ // Project includes #include "includes/define.h" #include "includes/model_part.h" -#include "expression/container_expression.h" +#include "tensor_adaptors/combined_tensor_adaptor.h" // Application includes @@ -42,8 +42,6 @@ class KRATOS_API(OPTIMIZATION_APPLICATION) LinearStrainEnergyResponseUtils using PhysicalFieldVariableTypes = std::variant*, const Variable>*>; - using ContainerExpressionType = std::variant::Pointer, ContainerExpression::Pointer, ContainerExpression::Pointer>; - ///@} ///@name Static operations ///@{ @@ -54,7 +52,7 @@ class KRATOS_API(OPTIMIZATION_APPLICATION) LinearStrainEnergyResponseUtils const PhysicalFieldVariableTypes& rPhysicalVariable, ModelPart& rGradientRequiredModelPart, ModelPart& rGradientComputedModelPart, - std::vector& rListOfContainerExpressions, + CombinedTensorAdaptor& rCombinedTensorAdaptor, const double PerturbationSize); ///@} From 262d261a4ed58c764e817a1b21a3889b02ff5e62 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Mon, 22 Dec 2025 22:27:23 +0100 Subject: [PATCH 008/116] fix resp utils python exposure --- .../custom_python/add_custom_response_utilities_to_python.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/OptimizationApplication/custom_python/add_custom_response_utilities_to_python.cpp b/applications/OptimizationApplication/custom_python/add_custom_response_utilities_to_python.cpp index 3063c4d5f952..2091cdfeef36 100644 --- a/applications/OptimizationApplication/custom_python/add_custom_response_utilities_to_python.cpp +++ b/applications/OptimizationApplication/custom_python/add_custom_response_utilities_to_python.cpp @@ -35,12 +35,12 @@ void AddCustomResponseUtilitiesToPython(pybind11::module& m) m.def_submodule("MassResponseUtils") .def("Check", &MassResponseUtils::Check) .def("CalculateValue", &MassResponseUtils::CalculateValue) - .def("CalculateGradient", &MassResponseUtils::CalculateGradient, py::arg("list_of_gradient_variables"), py::arg("list_of_gradient_required_model_parts"), py::arg("list_of_gradient_computed_model_parts"), py::arg("list_of_container_expressions"), py::arg("perturbation_size")) + .def("CalculateGradient", &MassResponseUtils::CalculateGradient, py::arg("physical_variable"), py::arg("gradient_required_model_parts"), py::arg("gradient_computed_model_parts"), py::arg("combined_tensor_adaptor"), py::arg("perturbation_size")) ; m.def_submodule("LinearStrainEnergyResponseUtils") .def("CalculateValue", &LinearStrainEnergyResponseUtils::CalculateValue) - .def("CalculateGradient", &LinearStrainEnergyResponseUtils::CalculateGradient, py::arg("list_of_gradient_variables"), py::arg("list_of_gradient_required_model_parts"), py::arg("list_of_gradient_computed_model_parts"), py::arg("list_of_container_expressions"), py::arg("perturbation_size")) + .def("CalculateGradient", &LinearStrainEnergyResponseUtils::CalculateGradient, py::arg("physical_variable"), py::arg("gradient_required_model_parts"), py::arg("gradient_computed_model_parts"), py::arg("combined_tensor_adaptor"), py::arg("perturbation_size")) ; m.def_submodule("MaxOverhangAngleResponseUtils") From 39b448bcf35c18ae533b8878fb67d88698af43d1 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Mon, 22 Dec 2025 22:27:57 +0100 Subject: [PATCH 009/116] add pGetContainer method for ContainerExps --- kratos/expression/container_expression.cpp | 27 +++++++++++++++++++ kratos/expression/container_expression.h | 2 ++ .../add_container_expression_to_python.cpp | 2 +- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/kratos/expression/container_expression.cpp b/kratos/expression/container_expression.cpp index 9441413be2b1..99286700c1a8 100644 --- a/kratos/expression/container_expression.cpp +++ b/kratos/expression/container_expression.cpp @@ -73,6 +73,9 @@ const ModelPart::MeshType& GetMesh(const ModelPart& rModelP template TContainerType& GetContainer(ModelPart::MeshType &rMesh); +template +typename TContainerType::Pointer pGetContainer(ModelPart::MeshType &rMesh); + template<> ModelPart::NodesContainerType& GetContainer(ModelPart::MeshType& rMesh) { @@ -91,6 +94,24 @@ ModelPart::ElementsContainerType& GetContainer return rMesh.Elements(); } +template<> +ModelPart::NodesContainerType::Pointer pGetContainer(ModelPart::MeshType& rMesh) +{ + return rMesh.pNodes(); +} + +template<> +ModelPart::ConditionsContainerType::Pointer pGetContainer(ModelPart::MeshType& rMesh) +{ + return rMesh.pConditions(); +} + +template<> +ModelPart::ElementsContainerType::Pointer pGetContainer(ModelPart::MeshType& rMesh) +{ + return rMesh.pElements(); +} + template const TContainerType& GetContainer(const ModelPart::MeshType &rMesh); @@ -223,6 +244,12 @@ TContainerType& ContainerExpression::GetContainer() return ContainerExpressionHelperUtilities::GetContainer(ContainerExpressionHelperUtilities::GetMesh(*mpModelPart)); } +template +typename TContainerType::Pointer ContainerExpression::pGetContainer() +{ + return ContainerExpressionHelperUtilities::pGetContainer(ContainerExpressionHelperUtilities::GetMesh(*mpModelPart)); +} + template const TContainerType& ContainerExpression::GetContainer() const { diff --git a/kratos/expression/container_expression.h b/kratos/expression/container_expression.h index 8be6d04dcfef..e36bdd28950b 100644 --- a/kratos/expression/container_expression.h +++ b/kratos/expression/container_expression.h @@ -211,6 +211,8 @@ class KRATOS_API(KRATOS_CORE) ContainerExpression { */ TContainerType& GetContainer(); + typename TContainerType::Pointer pGetContainer(); + /** * @brief Get the Container of the model part * diff --git a/kratos/python/add_container_expression_to_python.cpp b/kratos/python/add_container_expression_to_python.cpp index 0122e5d5aa5e..2e524f560850 100644 --- a/kratos/python/add_container_expression_to_python.cpp +++ b/kratos/python/add_container_expression_to_python.cpp @@ -45,7 +45,7 @@ void AddContainerExpressionToPython(pybind11::module& m, const std::string& rNam .def("HasExpression", &container_expression_holder_base::HasExpression) .def("GetExpression", &container_expression_holder_base::pGetExpression) .def("GetModelPart", py::overload_cast<>(&container_expression_holder_base::GetModelPart), py::return_value_policy::reference) - .def("GetContainer", py::overload_cast<>(&container_expression_holder_base::GetContainer), py::return_value_policy::reference) + .def("GetContainer", &container_expression_holder_base::pGetContainer) .def("GetItemShape", &container_expression_holder_base::GetItemShape) .def("GetItemComponentCount", &container_expression_holder_base::GetItemComponentCount) .def("GetMaxDepth", &container_expression_holder_base::GetMaxDepth) From 517a801a1e690e909344d63bb860c3dc53a06546 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Mon, 22 Dec 2025 22:28:27 +0100 Subject: [PATCH 010/116] update python linear strain energy resp to TA --- .../linear_strain_energy_response_function.py | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/applications/OptimizationApplication/python_scripts/responses/linear_strain_energy_response_function.py b/applications/OptimizationApplication/python_scripts/responses/linear_strain_energy_response_function.py index 1b3a2afff277..8dc27d87a3af 100644 --- a/applications/OptimizationApplication/python_scripts/responses/linear_strain_energy_response_function.py +++ b/applications/OptimizationApplication/python_scripts/responses/linear_strain_energy_response_function.py @@ -67,14 +67,40 @@ def CalculateGradient(self, physical_variable_collective_expressions: 'dict[Supp # now get the intersected model parts intersected_model_part_map = ModelPartUtilities.GetIntersectedMap(self.model_part, merged_model_part_map, True) + # TODO: Remove this block once everything is updated to TensorAdaptors + # ========================================================= + physical_variable_combined_tensor_adaptors: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]' = {} + for physical_variable, collective_expression in physical_variable_collective_expressions.items(): + ta_list = [] + for ce in collective_expression.GetContainerExpressions(): + if isinstance(physical_variable, Kratos.DoubleVariable): + shape = Kratos.DenseVectorUnsignedInt([len(ce.GetContainer())]) + elif isinstance(physical_variable, Kratos.Array1DVariable3): + shape = Kratos.DenseVectorUnsignedInt([len(ce.GetContainer()), 3]) + else: + raise RuntimeError("Unsupported type") + + ta_list.append(Kratos.TensorAdaptors.DoubleTensorAdaptor(ce.GetContainer(), Kratos.DoubleNDData(shape), copy=False)) + cta = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(ta_list, False, False) + cta.CollectData() + physical_variable_combined_tensor_adaptors[physical_variable] = cta + # ========================================================= + # calculate the gradients for physical_variable, merged_model_part in merged_model_part_map.items(): KratosOA.ResponseUtils.LinearStrainEnergyResponseUtils.CalculateGradient( physical_variable, merged_model_part, intersected_model_part_map[physical_variable], - physical_variable_collective_expressions[physical_variable].GetContainerExpressions(), + physical_variable_combined_tensor_adaptors[physical_variable], self.perturbation_size) + # TODO: Remove this block once everything is updated to TensorAdaptors + # ========================================================= + for physical_variable, collective_expression in physical_variable_collective_expressions.items(): + for i, ce in enumerate(collective_expression.GetContainerExpressions()): + Kratos.Expression.CArrayExpressionIO.Read(ce, physical_variable_combined_tensor_adaptors[physical_variable].GetTensorAdaptors()[i].data) + # ========================================================= + def __str__(self) -> str: return f"Response [type = {self.__class__.__name__}, name = {self.GetName()}, model part name = {self.model_part.FullName()}]" \ No newline at end of file From 29cad0c2983e87d56cf0fabbee118d925a77925d Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Mon, 22 Dec 2025 22:28:37 +0100 Subject: [PATCH 011/116] update mass response to TA --- .../responses/mass_response_function.py | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/applications/OptimizationApplication/python_scripts/responses/mass_response_function.py b/applications/OptimizationApplication/python_scripts/responses/mass_response_function.py index df1250d6d07b..4fe9ed15da6a 100644 --- a/applications/OptimizationApplication/python_scripts/responses/mass_response_function.py +++ b/applications/OptimizationApplication/python_scripts/responses/mass_response_function.py @@ -67,14 +67,40 @@ def CalculateGradient(self, physical_variable_collective_expressions: 'dict[Supp # now get the intersected model parts intersected_model_part_map = ModelPartUtilities.GetIntersectedMap(self.model_part, merged_model_part_map, False) + # TODO: Remove this block once everything is updated to TensorAdaptors + # ========================================================= + physical_variable_combined_tensor_adaptors: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]' = {} + for physical_variable, collective_expression in physical_variable_collective_expressions.items(): + ta_list = [] + for ce in collective_expression.GetContainerExpressions(): + if isinstance(physical_variable, Kratos.DoubleVariable): + shape = Kratos.DenseVectorUnsignedInt([len(ce.GetContainer())]) + elif isinstance(physical_variable, Kratos.Array1DVariable3): + shape = Kratos.DenseVectorUnsignedInt([len(ce.GetContainer()), 3]) + else: + raise RuntimeError("Unsupported type") + + ta_list.append(Kratos.TensorAdaptors.DoubleTensorAdaptor(ce.GetContainer(), Kratos.DoubleNDData(shape), copy=False)) + cta = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(ta_list, False, False) + cta.CollectData() + physical_variable_combined_tensor_adaptors[physical_variable] = cta + # ========================================================= + # calculate the gradients for physical_variable, merged_model_part in merged_model_part_map.items(): KratosOA.ResponseUtils.MassResponseUtils.CalculateGradient( physical_variable, merged_model_part, intersected_model_part_map[physical_variable], - physical_variable_collective_expressions[physical_variable].GetContainerExpressions(), + physical_variable_combined_tensor_adaptors[physical_variable], self.perturbation_size) + # TODO: Remove this block once everything is updated to TensorAdaptors + # ========================================================= + for physical_variable, collective_expression in physical_variable_collective_expressions.items(): + for i, ce in enumerate(collective_expression.GetContainerExpressions()): + Kratos.Expression.CArrayExpressionIO.Read(ce, physical_variable_combined_tensor_adaptors[physical_variable].GetTensorAdaptors()[i].data) + # ========================================================= + def __str__(self) -> str: return f"Response [type = {self.__class__.__name__}, name = {self.GetName()}, model part name = {self.model_part.FullName()}]" \ No newline at end of file From c6bfa8075af6435bfbfb3773fe6a6a9467bc513e Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Tue, 23 Dec 2025 00:30:50 +0100 Subject: [PATCH 012/116] response utils minor update --- .../response/linear_strain_energy_response_utils.cpp | 3 +++ .../custom_utilities/response/mass_response_utils.cpp | 3 +++ .../responses/linear_strain_energy_response_function.py | 1 - .../python_scripts/responses/mass_response_function.py | 1 - 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/applications/OptimizationApplication/custom_utilities/response/linear_strain_energy_response_utils.cpp b/applications/OptimizationApplication/custom_utilities/response/linear_strain_energy_response_utils.cpp index 84b9862f720e..e2fff7412269 100644 --- a/applications/OptimizationApplication/custom_utilities/response/linear_strain_energy_response_utils.cpp +++ b/applications/OptimizationApplication/custom_utilities/response/linear_strain_energy_response_utils.cpp @@ -139,6 +139,9 @@ void LinearStrainEnergyResponseUtils::CalculateGradient( } }, rPhysicalVariable); + // update the combined tensor adaptor flat vector. + rCombinedTensorAdaptor.CollectData(); + KRATOS_CATCH(""); } diff --git a/applications/OptimizationApplication/custom_utilities/response/mass_response_utils.cpp b/applications/OptimizationApplication/custom_utilities/response/mass_response_utils.cpp index 6c6f8eefeb1e..8860198c9eb2 100644 --- a/applications/OptimizationApplication/custom_utilities/response/mass_response_utils.cpp +++ b/applications/OptimizationApplication/custom_utilities/response/mass_response_utils.cpp @@ -186,6 +186,9 @@ void MassResponseUtils::CalculateGradient( } }, rPhysicalVariable); + // update the combined tensor adaptor flat vector. + rCombinedTensorAdaptor.CollectData(); + KRATOS_CATCH(""); } diff --git a/applications/OptimizationApplication/python_scripts/responses/linear_strain_energy_response_function.py b/applications/OptimizationApplication/python_scripts/responses/linear_strain_energy_response_function.py index 8dc27d87a3af..e9759c488553 100644 --- a/applications/OptimizationApplication/python_scripts/responses/linear_strain_energy_response_function.py +++ b/applications/OptimizationApplication/python_scripts/responses/linear_strain_energy_response_function.py @@ -82,7 +82,6 @@ def CalculateGradient(self, physical_variable_collective_expressions: 'dict[Supp ta_list.append(Kratos.TensorAdaptors.DoubleTensorAdaptor(ce.GetContainer(), Kratos.DoubleNDData(shape), copy=False)) cta = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(ta_list, False, False) - cta.CollectData() physical_variable_combined_tensor_adaptors[physical_variable] = cta # ========================================================= diff --git a/applications/OptimizationApplication/python_scripts/responses/mass_response_function.py b/applications/OptimizationApplication/python_scripts/responses/mass_response_function.py index 4fe9ed15da6a..407a807661af 100644 --- a/applications/OptimizationApplication/python_scripts/responses/mass_response_function.py +++ b/applications/OptimizationApplication/python_scripts/responses/mass_response_function.py @@ -82,7 +82,6 @@ def CalculateGradient(self, physical_variable_collective_expressions: 'dict[Supp ta_list.append(Kratos.TensorAdaptors.DoubleTensorAdaptor(ce.GetContainer(), Kratos.DoubleNDData(shape), copy=False)) cta = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(ta_list, False, False) - cta.CollectData() physical_variable_combined_tensor_adaptors[physical_variable] = cta # ========================================================= From a307c6eb4f8dbac9eea52ce2948c12d5e6c446f6 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Tue, 23 Dec 2025 00:31:24 +0100 Subject: [PATCH 013/116] update sigmoidal utils to TA --- .../control/sigmoidal_projection_utils.cpp | 109 ++++++------------ .../control/sigmoidal_projection_utils.h | 17 ++- 2 files changed, 40 insertions(+), 86 deletions(-) diff --git a/applications/OptimizationApplication/custom_utilities/control/sigmoidal_projection_utils.cpp b/applications/OptimizationApplication/custom_utilities/control/sigmoidal_projection_utils.cpp index e47b669b9b10..0b1e6e23264c 100644 --- a/applications/OptimizationApplication/custom_utilities/control/sigmoidal_projection_utils.cpp +++ b/applications/OptimizationApplication/custom_utilities/control/sigmoidal_projection_utils.cpp @@ -15,7 +15,6 @@ #include // Project includes -#include "expression/literal_flat_expression.h" #include "includes/define.h" #include "utilities/parallel_utilities.h" @@ -147,9 +146,8 @@ double ComputeFirstDerivativeAtValue( namespace Kratos { -template -ContainerExpression SigmoidalProjectionUtils::ProjectForward( - const ContainerExpression& rInputExpression, +TensorAdaptor::Pointer SigmoidalProjectionUtils::ProjectForward( + const TensorAdaptor& rInputTensorAdaptor, const std::vector& rXValues, const std::vector& rYValues, const double Beta, @@ -159,32 +157,24 @@ ContainerExpression SigmoidalProjectionUtils::ProjectForward( SigmoidalValueProjectionUtils::CheckXYVectors(rXValues,rYValues); - const auto& r_input_expression = rInputExpression.GetExpression(); - const IndexType local_size = rInputExpression.GetItemComponentCount(); - const IndexType number_of_entities = rInputExpression.GetContainer().size(); + const IndexType size = rInputTensorAdaptor.Size(); + auto input_data_view = rInputTensorAdaptor.ViewData(); - ContainerExpression output_container(*rInputExpression.pGetModelPart()); - auto p_flat_data_expression = LiteralFlatExpression::Create(number_of_entities, rInputExpression.GetItemShape()); - output_container.SetExpression(p_flat_data_expression); - auto& r_output_expression = *p_flat_data_expression; + auto p_nd_data = Kratos::make_shared>(rInputTensorAdaptor.Shape()); + auto p_result_tensor_adaptor = Kratos::make_shared>(rInputTensorAdaptor.GetContainer(), p_nd_data, false); + auto result_data_view = p_result_tensor_adaptor->ViewData(); - IndexPartition(number_of_entities).for_each([&r_input_expression, &r_output_expression, &rXValues, &rYValues, Beta, PenaltyFactor, local_size](const IndexType EntityIndex) { - const IndexType local_data_begin_index = EntityIndex * local_size; - for (IndexType i = 0; i < local_size; ++i) { - const double input_value = r_input_expression.Evaluate(EntityIndex, local_data_begin_index, i); - const double projected_value = SigmoidalValueProjectionUtils::ProjectValueForward(input_value, rXValues, rYValues, Beta, PenaltyFactor); - r_output_expression.SetData(local_data_begin_index, i, projected_value); - } - }); + IndexPartition(size).for_each([&input_data_view, &result_data_view, &rXValues, &rYValues, Beta, PenaltyFactor](const IndexType Index) { + result_data_view[Index] = SigmoidalValueProjectionUtils::ProjectValueForward(input_data_view[Index], rXValues, rYValues, Beta, PenaltyFactor); + }); - return output_container; + return p_result_tensor_adaptor; KRATOS_CATCH(""); } -template -ContainerExpression SigmoidalProjectionUtils::ProjectBackward( - const ContainerExpression& rInputExpression, +TensorAdaptor::Pointer SigmoidalProjectionUtils::ProjectBackward( + const TensorAdaptor& rInputTensorAdaptor, const std::vector& rXValues, const std::vector& rYValues, const double Beta, @@ -194,32 +184,24 @@ ContainerExpression SigmoidalProjectionUtils::ProjectBackward( SigmoidalValueProjectionUtils::CheckXYVectors(rXValues,rYValues); - const auto& r_input_expression = rInputExpression.GetExpression(); - const IndexType local_size = rInputExpression.GetItemComponentCount(); - const IndexType number_of_entities = rInputExpression.GetContainer().size(); + const IndexType size = rInputTensorAdaptor.Size(); + auto input_data_view = rInputTensorAdaptor.ViewData(); - ContainerExpression output_container(*rInputExpression.pGetModelPart()); - auto p_flat_data_expression = LiteralFlatExpression::Create(number_of_entities, rInputExpression.GetItemShape()); - output_container.SetExpression(p_flat_data_expression); - auto& r_output_expression = *p_flat_data_expression; + auto p_nd_data = Kratos::make_shared>(rInputTensorAdaptor.Shape()); + auto p_result_tensor_adaptor = Kratos::make_shared>(rInputTensorAdaptor.GetContainer(), p_nd_data, false); + auto result_data_view = p_result_tensor_adaptor->ViewData(); - IndexPartition(number_of_entities).for_each([&r_input_expression, &r_output_expression, &rXValues, &rYValues, Beta, PenaltyFactor, local_size](const IndexType EntityIndex) { - const IndexType local_data_begin_index = EntityIndex * local_size; - for (IndexType i = 0; i < local_size; ++i) { - const double input_value = r_input_expression.Evaluate(EntityIndex, local_data_begin_index, i); - const double projected_value = SigmoidalValueProjectionUtils::ProjectValueBackward(input_value, rXValues, rYValues, Beta, PenaltyFactor); - r_output_expression.SetData(local_data_begin_index, i, projected_value); - } - }); + IndexPartition(size).for_each([&input_data_view, &result_data_view, &rXValues, &rYValues, Beta, PenaltyFactor](const IndexType Index) { + result_data_view[Index] = SigmoidalValueProjectionUtils::ProjectValueBackward(input_data_view[Index], rXValues, rYValues, Beta, PenaltyFactor); + }); - return output_container; + return p_result_tensor_adaptor; KRATOS_CATCH(""); } -template -ContainerExpression SigmoidalProjectionUtils::CalculateForwardProjectionGradient( - const ContainerExpression& rInputExpression, +TensorAdaptor::Pointer SigmoidalProjectionUtils::CalculateForwardProjectionGradient( + const TensorAdaptor& rInputTensorAdaptor, const std::vector& rXValues, const std::vector& rYValues, const double Beta, @@ -229,45 +211,20 @@ ContainerExpression SigmoidalProjectionUtils::CalculateForwardPr SigmoidalValueProjectionUtils::CheckXYVectors(rXValues,rYValues); - const auto& r_input_expression = rInputExpression.GetExpression(); - const IndexType local_size = rInputExpression.GetItemComponentCount(); - const IndexType number_of_entities = rInputExpression.GetContainer().size(); + const IndexType size = rInputTensorAdaptor.Size(); + auto input_data_view = rInputTensorAdaptor.ViewData(); - ContainerExpression output_container(*rInputExpression.pGetModelPart()); - auto p_flat_data_expression = LiteralFlatExpression::Create(number_of_entities, rInputExpression.GetItemShape()); - output_container.SetExpression(p_flat_data_expression); - auto& r_output_expression = *p_flat_data_expression; + auto p_nd_data = Kratos::make_shared>(rInputTensorAdaptor.Shape()); + auto p_result_tensor_adaptor = Kratos::make_shared>(rInputTensorAdaptor.GetContainer(), p_nd_data, false); + auto result_data_view = p_result_tensor_adaptor->ViewData(); - IndexPartition(number_of_entities).for_each([&r_input_expression, &r_output_expression, &rXValues, &rYValues, Beta, PenaltyFactor, local_size](const IndexType EntityIndex) { - const IndexType local_data_begin_index = EntityIndex * local_size; - for (IndexType i = 0; i < local_size; ++i) { - const double input_value = r_input_expression.Evaluate(EntityIndex, local_data_begin_index, i); - const double derivative_value = SigmoidalValueProjectionUtils::ComputeFirstDerivativeAtValue(input_value, rXValues, rYValues, Beta, PenaltyFactor); - r_output_expression.SetData(local_data_begin_index, i, derivative_value); - } - }); + IndexPartition(size).for_each([&input_data_view, &result_data_view, &rXValues, &rYValues, Beta, PenaltyFactor](const IndexType Index) { + result_data_view[Index] = SigmoidalValueProjectionUtils::ComputeFirstDerivativeAtValue(input_data_view[Index], rXValues, rYValues, Beta, PenaltyFactor); + }); - return output_container; + return p_result_tensor_adaptor; KRATOS_CATCH(""); } -// template instantiations -#define KRATOS_INSTANTIATE_SIGMOIDAL_PROJECTION_UTIL_METHODS(CONTAINER_TYPE) \ - template KRATOS_API(OPTIMIZATION_APPLICATION) ContainerExpression SigmoidalProjectionUtils::ProjectForward( \ - const ContainerExpression&, const std::vector&, \ - const std::vector&, const double, const int); \ - template KRATOS_API(OPTIMIZATION_APPLICATION) ContainerExpression SigmoidalProjectionUtils::ProjectBackward( \ - const ContainerExpression&, const std::vector&, \ - const std::vector&, const double, const int); \ - template KRATOS_API(OPTIMIZATION_APPLICATION) ContainerExpression SigmoidalProjectionUtils::CalculateForwardProjectionGradient( \ - const ContainerExpression&, const std::vector&, \ - const std::vector&, const double, const int); - -KRATOS_INSTANTIATE_SIGMOIDAL_PROJECTION_UTIL_METHODS(ModelPart::NodesContainerType) -KRATOS_INSTANTIATE_SIGMOIDAL_PROJECTION_UTIL_METHODS(ModelPart::ConditionsContainerType) -KRATOS_INSTANTIATE_SIGMOIDAL_PROJECTION_UTIL_METHODS(ModelPart::ElementsContainerType) - -#undef KRATOS_INSTANTIATE_SIGMOIDAL_PROJECTION_UTIL_METHODS -///@} } \ No newline at end of file diff --git a/applications/OptimizationApplication/custom_utilities/control/sigmoidal_projection_utils.h b/applications/OptimizationApplication/custom_utilities/control/sigmoidal_projection_utils.h index 409a6f593b39..30e590f45e6c 100644 --- a/applications/OptimizationApplication/custom_utilities/control/sigmoidal_projection_utils.h +++ b/applications/OptimizationApplication/custom_utilities/control/sigmoidal_projection_utils.h @@ -18,7 +18,7 @@ // Project includes #include "includes/define.h" -#include "expression/container_expression.h" +#include "tensor_adaptors/tensor_adaptor.h" // Application includes @@ -40,25 +40,22 @@ class KRATOS_API(OPTIMIZATION_APPLICATION) SigmoidalProjectionUtils ///@name Static operations ///@{ - template - static ContainerExpression ProjectForward( - const ContainerExpression& rInputExpression, + static TensorAdaptor::Pointer ProjectForward( + const TensorAdaptor& rInputTensorAdaptor, const std::vector& rXValues, const std::vector& rYValues, const double Beta, const int PenaltyFactor); - template - static ContainerExpression ProjectBackward( - const ContainerExpression& rInputExpression, + static TensorAdaptor::Pointer ProjectBackward( + const TensorAdaptor& rInputTensorAdaptor, const std::vector& rXValues, const std::vector& rYValues, const double Beta, const int PenaltyFactor); - template - static ContainerExpression CalculateForwardProjectionGradient( - const ContainerExpression& rInputExpression, + static TensorAdaptor::Pointer CalculateForwardProjectionGradient( + const TensorAdaptor& rInputTensorAdaptor, const std::vector& rXValues, const std::vector& rYValues, const double Beta, From e3314b295c233c22b591bf51d6a729d334397a34 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Tue, 23 Dec 2025 00:33:48 +0100 Subject: [PATCH 014/116] update sigmoidal python exp to TA --- ...add_custom_control_utilities_to_python.cpp | 28 +++---------------- 1 file changed, 4 insertions(+), 24 deletions(-) diff --git a/applications/OptimizationApplication/custom_python/add_custom_control_utilities_to_python.cpp b/applications/OptimizationApplication/custom_python/add_custom_control_utilities_to_python.cpp index c0db299cbcd4..1ed9e339226a 100644 --- a/applications/OptimizationApplication/custom_python/add_custom_control_utilities_to_python.cpp +++ b/applications/OptimizationApplication/custom_python/add_custom_control_utilities_to_python.cpp @@ -28,34 +28,14 @@ namespace Kratos { namespace Python { -namespace detail -{ -template -void AddSigmoidalProjectionUtils(pybind11::module& m) +void AddCustomControlUtilitiesToPython(pybind11::module& m) { namespace py = pybind11; - std::string container_type; - if constexpr(std::is_same_v) { - container_type = "nodal_expression"; - } else if constexpr(std::is_same_v) { - container_type = "condition_expression"; - } else { - container_type = "element_expression"; - } - - m.def("ProjectForward", &SigmoidalProjectionUtils::ProjectForward, py::arg(container_type.c_str()), py::arg("x_values"), py::arg("y_values"), py::arg("beta"), py::arg("penalty_factor")); - m.def("ProjectBackward", &SigmoidalProjectionUtils::ProjectBackward, py::arg(container_type.c_str()), py::arg("x_values"), py::arg("y_values"), py::arg("beta"), py::arg("penalty_factor")); - m.def("CalculateForwardProjectionGradient", &SigmoidalProjectionUtils::CalculateForwardProjectionGradient, py::arg(container_type.c_str()), py::arg("x_values"), py::arg("y_values"), py::arg("beta"), py::arg("penalty_factor")); -} -} // namespace detail - -void AddCustomControlUtilitiesToPython(pybind11::module& m) -{ auto module = m.def_submodule("SigmoidalProjectionUtils"); - detail::AddSigmoidalProjectionUtils(module); - detail::AddSigmoidalProjectionUtils(module); - detail::AddSigmoidalProjectionUtils(module); + module.def("ProjectForward", &SigmoidalProjectionUtils::ProjectForward, py::arg("input_tensor_adaptor"), py::arg("x_values"), py::arg("y_values"), py::arg("beta"), py::arg("penalty_factor")); + module.def("ProjectBackward", &SigmoidalProjectionUtils::ProjectBackward, py::arg("input_tensor_adaptor"), py::arg("x_values"), py::arg("y_values"), py::arg("beta"), py::arg("penalty_factor")); + module.def("CalculateForwardProjectionGradient", &SigmoidalProjectionUtils::CalculateForwardProjectionGradient, py::arg("input_tensor_adaptor"), py::arg("x_values"), py::arg("y_values"), py::arg("beta"), py::arg("penalty_factor")); } } // namespace Python. From 885f3bd026ac39b2b7ec963cadfd4e715c70bd64 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Tue, 23 Dec 2025 00:34:19 +0100 Subject: [PATCH 015/116] update sigmoidal proj utils tests to TA --- .../tests/test_sigmoidal_projection.py | 108 +++++++++--------- 1 file changed, 55 insertions(+), 53 deletions(-) diff --git a/applications/OptimizationApplication/tests/test_sigmoidal_projection.py b/applications/OptimizationApplication/tests/test_sigmoidal_projection.py index 27e52123c5d0..da42a51ab0e0 100644 --- a/applications/OptimizationApplication/tests/test_sigmoidal_projection.py +++ b/applications/OptimizationApplication/tests/test_sigmoidal_projection.py @@ -1,3 +1,4 @@ +import numpy import KratosMultiphysics as Kratos import KratosMultiphysics.OptimizationApplication as KratosOA from KratosMultiphysics.KratosUnittest import TestCase @@ -11,11 +12,11 @@ def setUpClass(cls): cls.test_model_part.CreateNewNode(1, 0.0,0.0,0.0) - def _GetContainerExpression(self): - return Kratos.Expression.NodalExpression(self.test_model_part) + def _GetTensorAdaptor(self): + return Kratos.TensorAdaptors.DoubleTensorAdaptor(self.test_model_part.Nodes, Kratos.DoubleNDData([self.test_model_part.NumberOfNodes()]), copy = False) def test_ProjectForward(self): - test_field = self._GetContainerExpression() + test_field = self._GetTensorAdaptor() with self.assertRaises(RuntimeError): _ = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectForward(test_field,[1],[2],25.0,1) with self.assertRaises(RuntimeError): @@ -31,52 +32,52 @@ def test_ProjectForward(self): with self.assertRaises(RuntimeError): _ = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectForward(test_field,[1,2],[4,3],25.0,1) - Kratos.Expression.LiteralExpressionIO.SetData(test_field, 1.5) + test_field.data[:] = 1.5 forward_projected_field = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectForward(test_field,[1,2],[3,4],25.0,1) - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(forward_projected_field), 3.5, 4) + self.assertAlmostEqual(numpy.linalg.norm(forward_projected_field.data), 3.5, 4) forward_projected_field = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectForward(test_field,[1,2],[3,4],25.0,4) - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(forward_projected_field), 3.0625, 4) + self.assertAlmostEqual(numpy.linalg.norm(forward_projected_field.data), 3.0625, 4) - Kratos.Expression.LiteralExpressionIO.SetData(test_field, 5.0) + test_field.data[:] = 5.0 forward_projected_field = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectForward(test_field,[1,2],[3,4],25.0,1) - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(forward_projected_field), 4.0, 4) + self.assertAlmostEqual(numpy.linalg.norm(forward_projected_field.data), 4.0, 4) - Kratos.Expression.LiteralExpressionIO.SetData(test_field, -10.0) + test_field.data[:] = -10.0 forward_projected_field = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectForward(test_field,[1,2],[3,4],25.0,1) - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(forward_projected_field), 3.0, 4) + self.assertAlmostEqual(numpy.linalg.norm(forward_projected_field.data), 3.0, 4) - Kratos.Expression.LiteralExpressionIO.SetData(test_field, 1.51) + test_field.data[:] = 1.51 forward_projected_field = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectForward(test_field,[1,2],[3,4],25.0,1) - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(forward_projected_field), 3.6224593312018545, 10) + self.assertAlmostEqual(numpy.linalg.norm(forward_projected_field.data), 3.6224593312018545, 10) forward_projected_field = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectForward(test_field,[1,2],[3,4],25.0,4) - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(forward_projected_field), 3.1501218566948745, 10) + self.assertAlmostEqual(numpy.linalg.norm(forward_projected_field.data), 3.1501218566948745, 10) - Kratos.Expression.LiteralExpressionIO.SetData(test_field, 1.49) + test_field.data[:] = 1.49 forward_projected_field = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectForward(test_field,[1,2],[3,4],25.0,1) - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(forward_projected_field), 3.3775406687981455, 10) + self.assertAlmostEqual(numpy.linalg.norm(forward_projected_field.data), 3.3775406687981455, 10) forward_projected_field = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectForward(test_field,[1,2],[3,4],25.0,4) - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(forward_projected_field), 3.020316783995807, 10) + self.assertAlmostEqual(numpy.linalg.norm(forward_projected_field.data), 3.020316783995807, 10) - Kratos.Expression.LiteralExpressionIO.SetData(test_field, 2.5) + test_field.data[:] = 2.5 forward_projected_field = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectForward(test_field,[1,2,3],[4,5,6],25.0,1) - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(forward_projected_field), 5.5, 4) + self.assertAlmostEqual(numpy.linalg.norm(forward_projected_field.data), 5.5, 4) forward_projected_field = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectForward(test_field,[1,2,3],[4,5,6],25.0,4) - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(forward_projected_field), 5.0625, 4) + self.assertAlmostEqual(numpy.linalg.norm(forward_projected_field.data), 5.0625, 4) - Kratos.Expression.LiteralExpressionIO.SetData(test_field, 2.0) + test_field.data[:] = 2.0 forward_projected_field = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectForward(test_field,[1,2,3],[4,5,6],25.0,1) - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(forward_projected_field), 5.0, 4) + self.assertAlmostEqual(numpy.linalg.norm(forward_projected_field.data), 5.0, 4) - Kratos.Expression.LiteralExpressionIO.SetData(test_field, 1.0) + test_field.data[:] = 1.0 forward_projected_field = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectForward(test_field,[1,2,3],[4,5,6],25.0,1) - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(forward_projected_field), 4.0, 4) + self.assertAlmostEqual(numpy.linalg.norm(forward_projected_field.data), 4.0, 4) - Kratos.Expression.LiteralExpressionIO.SetData(test_field, 3.0) + test_field.data[:] = 3.0 forward_projected_field = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectForward(test_field,[1,2,3],[4,5,6],25.0,1) - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(forward_projected_field), 6.0, 4) + self.assertAlmostEqual(numpy.linalg.norm(forward_projected_field.data), 6.0, 4) def test_ProjectBackward(self): - test_field = self._GetContainerExpression() + test_field = self._GetTensorAdaptor() with self.assertRaises(RuntimeError): _ = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectBackward(test_field,[1],[2],25.0,1) with self.assertRaises(RuntimeError): @@ -91,62 +92,63 @@ def test_ProjectBackward(self): _ = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectBackward(test_field,[2,1],[3,4],25.0,1) with self.assertRaises(RuntimeError): _ = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectBackward(test_field,[1,2],[4,3],25.0,1) - Kratos.Expression.LiteralExpressionIO.SetData(test_field, 5.5) + + test_field.data[:] = 5.5 with self.assertRaises(RuntimeError): _ = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectBackward(test_field,[1,2],[3,4],25.0,1) - Kratos.Expression.LiteralExpressionIO.SetData(test_field, 2.5) + test_field.data[:] = 2.5 with self.assertRaises(RuntimeError): _ = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectBackward(test_field,[1,2],[3,4],25.0,1) - Kratos.Expression.LiteralExpressionIO.SetData(test_field, 5.5) + test_field.data[:] = 5.5 backward_projected_field = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectBackward(test_field,[1,2,3],[4,5,6],25.0,1) - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(backward_projected_field), 2.5, 4) + self.assertAlmostEqual(numpy.linalg.norm(backward_projected_field.data), 2.5, 4) backward_projected_field = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectBackward(test_field,[1,2,3],[4,5,6],25.0,4) - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(backward_projected_field), 2.5332982603469762, 10) + self.assertAlmostEqual(numpy.linalg.norm(backward_projected_field.data), 2.5332982603469762, 10) - Kratos.Expression.LiteralExpressionIO.SetData(test_field, 5.999999999) + test_field.data[:] = 5.999999999 backward_projected_field = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectBackward(test_field,[1,2,3],[4,5,6],25.0,1) - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(backward_projected_field), 2.914465315084121, 10) + self.assertAlmostEqual(numpy.linalg.norm(backward_projected_field.data), 2.914465315084121, 10) backward_projected_field = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectBackward(test_field,[1,2,3],[4,5,6],25.0,4) - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(backward_projected_field), 2.942191202306519, 10) + self.assertAlmostEqual(numpy.linalg.norm(backward_projected_field.data), 2.942191202306519, 10) - Kratos.Expression.LiteralExpressionIO.SetData(test_field, 4.5) + test_field.data[:] = 4.5 backward_projected_field = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectBackward(test_field,[1,2,3],[4,5,6],25.0,1) - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(backward_projected_field), 1.5, 4) + self.assertAlmostEqual(numpy.linalg.norm(backward_projected_field.data), 1.5, 4) - Kratos.Expression.LiteralExpressionIO.SetData(test_field, 4.0) + test_field.data[:] = 4.0 backward_projected_field = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectBackward(test_field,[1,2,3],[4,5,6],25.0,1) - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(backward_projected_field), 1.0, 4) + self.assertAlmostEqual(numpy.linalg.norm(backward_projected_field.data), 1.0, 4) - Kratos.Expression.LiteralExpressionIO.SetData(test_field, 5.0) + test_field.data[:] = 5.0 backward_projected_field = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectBackward(test_field,[1,2,3],[4,5,6],25.0,1) - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(backward_projected_field), 2.0, 4) + self.assertAlmostEqual(numpy.linalg.norm(backward_projected_field.data), 2.0, 4) - Kratos.Expression.LiteralExpressionIO.SetData(test_field, 800.0) + test_field.data[:] = 800.0 backward_projected_field = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectBackward(test_field,[1,2,3],[400,420,1000],25.0,1) - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(backward_projected_field), 2.512837077723448, 10) + self.assertAlmostEqual(numpy.linalg.norm(backward_projected_field.data), 2.512837077723448, 10) backward_projected_field = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectBackward(test_field,[1,2,3],[400,420,1000],25.0,4) - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(backward_projected_field), 2.5438738644771486, 10) + self.assertAlmostEqual(numpy.linalg.norm(backward_projected_field.data), 2.5438738644771486, 10) def test_ComputeFirstDerivative(self): - test_field = self._GetContainerExpression() - Kratos.Expression.LiteralExpressionIO.SetData(test_field, 5.5) + test_field = self._GetTensorAdaptor() + test_field.data[:] = 5.5 derivative_field = KratosOA.ControlUtils.SigmoidalProjectionUtils.CalculateForwardProjectionGradient(test_field,[1,2,3],[4,5,6],25.0,1) - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(derivative_field), 0.0, 4) + self.assertAlmostEqual(numpy.linalg.norm(derivative_field.data), 0.0, 4) derivative_field = KratosOA.ControlUtils.SigmoidalProjectionUtils.CalculateForwardProjectionGradient(test_field,[1,2,3],[4,5,6],25.0,4) - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(derivative_field), 0.0, 4) + self.assertAlmostEqual(numpy.linalg.norm(derivative_field.data), 0.0, 4) - Kratos.Expression.LiteralExpressionIO.SetData(test_field, 2.5) + test_field.data[:] = 2.5 derivative_field = KratosOA.ControlUtils.SigmoidalProjectionUtils.CalculateForwardProjectionGradient(test_field,[1,2,3],[4,5,6],25.0,1) - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(derivative_field), 12.5, 4) + self.assertAlmostEqual(numpy.linalg.norm(derivative_field.data), 12.5, 4) derivative_field = KratosOA.ControlUtils.SigmoidalProjectionUtils.CalculateForwardProjectionGradient(test_field,[1,2,3],[4,5,6],25.0,4) - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(derivative_field), 6.25, 4) + self.assertAlmostEqual(numpy.linalg.norm(derivative_field.data), 6.25, 4) - Kratos.Expression.LiteralExpressionIO.SetData(test_field, 1.5) + test_field.data[:] = 1.5 derivative_field = KratosOA.ControlUtils.SigmoidalProjectionUtils.CalculateForwardProjectionGradient(test_field,[1,2,3],[0,500,600],25.0,1) - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(derivative_field), 6250.0, 4) + self.assertAlmostEqual(numpy.linalg.norm(derivative_field.data), 6250.0, 4) derivative_field = KratosOA.ControlUtils.SigmoidalProjectionUtils.CalculateForwardProjectionGradient(test_field,[1,2,3],[0,500,600],25.0,4) - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(derivative_field), 3125.0, 4) + self.assertAlmostEqual(numpy.linalg.norm(derivative_field.data), 3125.0, 4) if __name__ == '__main__': Kratos.KratosUnittest.main() \ No newline at end of file From e46673a8f63efbfe9a2e323cf58d1cf3cffd409e Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Tue, 23 Dec 2025 00:34:31 +0100 Subject: [PATCH 016/116] update opt_projection.py to TA --- .../utilities/opt_projection.py | 36 +++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/applications/OptimizationApplication/python_scripts/utilities/opt_projection.py b/applications/OptimizationApplication/python_scripts/utilities/opt_projection.py index b1cca426e05c..eaca8e58c123 100644 --- a/applications/OptimizationApplication/python_scripts/utilities/opt_projection.py +++ b/applications/OptimizationApplication/python_scripts/utilities/opt_projection.py @@ -119,13 +119,25 @@ def SetProjectionSpaces(self, x_space_values: 'list[float]', y_space_values: 'li self.y_space_values = y_space_values def ProjectForward(self, x_values: ContainerExpressionTypes) -> ContainerExpressionTypes: - return KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectForward(x_values, self.x_space_values, self.y_space_values, self.beta, self.penalty_factor) + ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(x_values.GetContainer(), Kratos.DoubleNDData(x_values.Evaluate()), copy=False) + result_ta = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectForward(ta, self.x_space_values, self.y_space_values, self.beta, self.penalty_factor) + result_exp = x_values.Clone() + Kratos.Expression.CArrayExpressionIO.Read(result_exp, result_ta.data) + return result_exp def ProjectBackward(self, y_values: ContainerExpressionTypes) -> ContainerExpressionTypes: - return KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectBackward(y_values, self.x_space_values, self.y_space_values, self.beta, self.penalty_factor) + ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(y_values.GetContainer(), Kratos.DoubleNDData(y_values.Evaluate()), copy=False) + result_ta = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectBackward(ta, self.x_space_values, self.y_space_values, self.beta, self.penalty_factor) + result_exp = y_values.Clone() + Kratos.Expression.CArrayExpressionIO.Read(result_exp, result_ta.data) + return result_exp def ForwardProjectionGradient(self, x_values: ContainerExpressionTypes) -> ContainerExpressionTypes: - return KratosOA.ControlUtils.SigmoidalProjectionUtils.CalculateForwardProjectionGradient(x_values, self.x_space_values, self.y_space_values, self.beta, self.penalty_factor) + ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(x_values.GetContainer(), Kratos.DoubleNDData(x_values.Evaluate()), copy=False) + result_ta = KratosOA.ControlUtils.SigmoidalProjectionUtils.CalculateForwardProjectionGradient(ta, self.x_space_values, self.y_space_values, self.beta, self.penalty_factor) + result_exp = x_values.Clone() + Kratos.Expression.CArrayExpressionIO.Read(result_exp, result_ta.data) + return result_exp def Update(self) -> None: pass @@ -159,13 +171,25 @@ def SetProjectionSpaces(self, x_space_values: 'list[float]', y_space_values: 'li self.y_space_values = y_space_values def ProjectForward(self, x_values: ContainerExpressionTypes) -> ContainerExpressionTypes: - return KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectForward(x_values, self.x_space_values, self.y_space_values, self.beta, self.penalty_factor) + ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(x_values.GetContainer(), Kratos.DoubleNDData(x_values.Evaluate()), copy=False) + result_ta = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectForward(ta, self.x_space_values, self.y_space_values, self.beta, self.penalty_factor) + result_exp = x_values.Clone() + Kratos.Expression.CArrayExpressionIO.Read(result_exp, result_ta.data) + return result_exp def ProjectBackward(self, y_values: ContainerExpressionTypes) -> ContainerExpressionTypes: - return KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectBackward(y_values, self.x_space_values, self.y_space_values, self.beta, self.penalty_factor) + ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(y_values.GetContainer(), Kratos.DoubleNDData(y_values.Evaluate()), copy=False) + result_ta = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectBackward(ta, self.x_space_values, self.y_space_values, self.beta, self.penalty_factor) + result_exp = y_values.Clone() + Kratos.Expression.CArrayExpressionIO.Read(result_exp, result_ta.data) + return result_exp def ForwardProjectionGradient(self, x_values: ContainerExpressionTypes) -> ContainerExpressionTypes: - return KratosOA.ControlUtils.SigmoidalProjectionUtils.CalculateForwardProjectionGradient(x_values, self.x_space_values, self.y_space_values, self.beta, self.penalty_factor) + ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(x_values.GetContainer(), Kratos.DoubleNDData(x_values.Evaluate()), copy=False) + result_ta = KratosOA.ControlUtils.SigmoidalProjectionUtils.CalculateForwardProjectionGradient(ta, self.x_space_values, self.y_space_values, self.beta, self.penalty_factor) + result_exp = x_values.Clone() + Kratos.Expression.CArrayExpressionIO.Read(result_exp, result_ta.data) + return result_exp def Update(self) -> None: step = self.optimization_problem.GetStep() From 48582af12c02309a00459499702756d75d6b2559 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 30 Jan 2026 12:40:01 +0100 Subject: [PATCH 017/116] change explicit damping --- .../custom_utilities/filtering/explicit_damping.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/applications/OptimizationApplication/custom_utilities/filtering/explicit_damping.h b/applications/OptimizationApplication/custom_utilities/filtering/explicit_damping.h index db4b1d0a4bf9..661f3b6bbbe6 100644 --- a/applications/OptimizationApplication/custom_utilities/filtering/explicit_damping.h +++ b/applications/OptimizationApplication/custom_utilities/filtering/explicit_damping.h @@ -17,8 +17,7 @@ // Project includes #include "includes/define.h" -#include "expression/expression.h" -#include "expression/container_expression.h" +#include "tensor_adaptors/tensor_adaptor.h" // Application includes #include "entity_point.h" @@ -61,7 +60,7 @@ class KRATOS_API(OPTIMIZATION_APPLICATION) ExplicitDamping /** * @brief Set the damping radius */ - virtual void SetRadius(const ContainerExpression& rExpression) + virtual void SetRadius(TensorAdaptor::Pointer pTensorAdaptor) { KRATOS_ERROR << "Calling base class ExplicitDamping::SetRadius. This should be implemented in the derived class."; } @@ -69,7 +68,7 @@ class KRATOS_API(OPTIMIZATION_APPLICATION) ExplicitDamping /** * @brief Get the used damping radius expression */ - virtual typename ContainerExpression::Pointer GetRadius() const + virtual TensorAdaptor::Pointer GetRadius() const { KRATOS_ERROR << "Calling base class ExplicitDamping::GetRadius. This should be implemented in the derived class."; return nullptr; From 9fe8fe99c709b5760728121b67ec58f3de5606ad Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 30 Jan 2026 12:40:43 +0100 Subject: [PATCH 018/116] explicit filter utils update --- .../filtering/explicit_filter_utils.cpp | 238 ++++++++++-------- .../filtering/explicit_filter_utils.h | 34 +-- 2 files changed, 145 insertions(+), 127 deletions(-) diff --git a/applications/OptimizationApplication/custom_utilities/filtering/explicit_filter_utils.cpp b/applications/OptimizationApplication/custom_utilities/filtering/explicit_filter_utils.cpp index f616148e3d64..953674c64b65 100644 --- a/applications/OptimizationApplication/custom_utilities/filtering/explicit_filter_utils.cpp +++ b/applications/OptimizationApplication/custom_utilities/filtering/explicit_filter_utils.cpp @@ -18,7 +18,6 @@ #include // Project includes -#include "expression/literal_flat_expression.h" #include "utilities/atomic_utilities.h" #include "utilities/builtin_timer.h" #include "utilities/model_part_utils.h" @@ -35,34 +34,28 @@ namespace Kratos { namespace ExplicitFilterUtilsHelperUtilities { template -Expression::ConstPointer GetNodalDomainSizeExpression( +void GetNodalDomainSizeExpression( + std::vector& rNodalDomainSizes, const TContainerType& rContainer, const ModelPart::NodesContainerType& rNodes) { const IndexType number_of_nodes = rNodes.size(); - auto p_expression = LiteralFlatExpression::Create(number_of_nodes, {}); + rNodalDomainSizes.resize(number_of_nodes, 0.0); - // reset the existing values in the expression - IndexPartition(number_of_nodes).for_each([&p_expression](const IndexType Index) { - *(p_expression->begin() + Index) = 0.0; - }); - - IndexPartition(rContainer.size()).for_each([&rNodes, &rContainer, &p_expression](const IndexType Index) { + IndexPartition(rContainer.size()).for_each([&rNodes, &rContainer, &rNodalDomainSizes](const IndexType Index) { const auto& r_geometry = (rContainer.begin() + Index)->GetGeometry(); const double nodal_domain_size = r_geometry.DomainSize() / r_geometry.size(); for (const auto& r_node : r_geometry) { const auto node_ptr = rNodes.find(r_node.Id()); if (node_ptr != rNodes.end()) { const IndexType node_index = std::distance(rNodes.begin(), node_ptr); - AtomicAdd(*(p_expression->begin() + node_index), nodal_domain_size); + AtomicAdd(rNodalDomainSizes[node_index], nodal_domain_size); } else { KRATOS_ERROR << "Node with id " << r_node.Id() << " not found."; } } }); - - return p_expression; } struct NodeCloudsType @@ -70,7 +63,7 @@ struct NodeCloudsType template static inline double GetDomainSize( const EntityPoint& rPoint, - Expression const * const pExpression) + const std::vector& rNodalDomainSizes) { if constexpr(!std::is_same_v) { KRATOS_ERROR << "Point / node clouds should only be used with nodes."; @@ -91,10 +84,10 @@ struct MeshIndependentType template static inline double GetDomainSize( const EntityPoint& rPoint, - Expression const * const pExpression) + const std::vector& rNodalDomainSizes) { if constexpr(std::is_same_v) { - return pExpression->Evaluate(rPoint.Id(), rPoint.Id(), 0); + return rNodalDomainSizes[rPoint.Id()]; } else { return rPoint.GetEntity().GetGeometry().DomainSize(); } @@ -113,10 +106,10 @@ struct MeshDependentType template static inline double GetDomainSize( const EntityPoint& rPoint, - Expression const * const pExpression) + const std::vector& rNodalDomainSizes) { if constexpr(std::is_same_v) { - return pExpression->Evaluate(rPoint.Id(), rPoint.Id(), 0); + return rNodalDomainSizes[rPoint.Id()]; } else { return rPoint.GetEntity().GetGeometry().DomainSize(); } @@ -140,10 +133,10 @@ void ComputeWeightForAllNeighbors( const std::vector::Pointer>& rNeighbourNodes, const std::vector& rSquaredDistances, const IndexType NumberOfNeighbours, - Expression const * const pExpression) + const std::vector& rNodalDomainSizes) { for (IndexType i = 0; i < NumberOfNeighbours; ++i) { - const double domain_size = TMeshDependencyType::GetDomainSize(*rNeighbourNodes[i], pExpression); + const double domain_size = TMeshDependencyType::GetDomainSize(*rNeighbourNodes[i], rNodalDomainSizes); const double filter_weight = rFilterFunction.ComputeWeight(Radius, std::sqrt(rSquaredDistances[i])) * domain_size; rListOfWeights[i] = filter_weight; rSumOfWeights += filter_weight; @@ -168,24 +161,42 @@ ExplicitFilterUtils::ExplicitFilterUtils( } template -void ExplicitFilterUtils::SetRadius(const ContainerExpression& rContainerExpression) +void ExplicitFilterUtils::SetRadius(TensorAdaptor::Pointer pTensorAdaptor) { - KRATOS_ERROR_IF_NOT(rContainerExpression.GetItemComponentCount() == 1) - << "Only scalar values are allowed for the filter radius container expression. " - << "Provided container expression = " << rContainerExpression << ".\n"; - - KRATOS_ERROR_IF_NOT(&rContainerExpression.GetModelPart() == &mrModelPart) - << "Filter radius container expression model part and filter model part mismatch." - << "\n\tFilter = " << *this - << "\n\tContainerExpression = " << rContainerExpression; + KRATOS_ERROR_IF_NOT(pTensorAdaptor->Shape().size() == 1) + << "Only scalar values are allowed for the filter radius tensor adaptor." + << "Provided tensor adaptor = " << *pTensorAdaptor << ".\n"; + + if (std::holds_alternative(pTensorAdaptor->GetContainer())) { + const auto& r_container = *(std::get(pTensorAdaptor->GetContainer())); + KRATOS_ERROR_IF_NOT(&r_container == &mrModelPart.Nodes() || &r_container == &mrModelPart.GetCommunicator().LocalMesh().Nodes()) + << "Filter radius container expression model part and filter model part mismatch." + << "\n\tFilter = " << *this + << "\n\tContainerExpression = " << *pTensorAdaptor; + } else if (std::holds_alternative(pTensorAdaptor->GetContainer())) { + const auto& r_container = *(std::get(pTensorAdaptor->GetContainer())); + KRATOS_ERROR_IF_NOT(&r_container == &mrModelPart.Conditions()) + << "Filter radius container expression model part and filter model part mismatch." + << "\n\tFilter = " << *this + << "\n\tContainerExpression = " << *pTensorAdaptor; + } else if (std::holds_alternative(pTensorAdaptor->GetContainer())) { + const auto& r_container = *(std::get(pTensorAdaptor->GetContainer())); + KRATOS_ERROR_IF_NOT(&r_container == &mrModelPart.Elements()) + << "Filter radius container expression model part and filter model part mismatch." + << "\n\tFilter = " << *this + << "\n\tContainerExpression = " << *pTensorAdaptor; + } else { + KRATOS_ERROR << "Unsupported container type is found in the tensor adaptor. Only supports nodal, condition or elemental tensor adaptors [ tensor adaptor = " + << *pTensorAdaptor << " ].\n"; + } - mpFilterRadiusContainer = rContainerExpression.Clone(); + mpFilterRadiusTensorAdaptor = pTensorAdaptor; } template -ContainerExpression ExplicitFilterUtils::GetRadius() const +TensorAdaptor::Pointer ExplicitFilterUtils::GetRadius() const { - return *mpFilterRadiusContainer; + return mpFilterRadiusTensorAdaptor; } template @@ -224,9 +235,9 @@ void ExplicitFilterUtils::ExplicitFilterUtils::Update() const IndexType number_of_elements = r_elements.size(); if (number_of_elements > 0) { - mpNodalDomainSizeExpression = ExplicitFilterUtilsHelperUtilities::GetNodalDomainSizeExpression(r_elements, r_nodes); + ExplicitFilterUtilsHelperUtilities::GetNodalDomainSizeExpression(mNodalDomainSizes, r_elements, r_nodes); } else if (number_of_conditions > 0) { - mpNodalDomainSizeExpression = ExplicitFilterUtilsHelperUtilities::GetNodalDomainSizeExpression(r_conditions, r_nodes); + ExplicitFilterUtilsHelperUtilities::GetNodalDomainSizeExpression(mNodalDomainSizes, r_conditions, r_nodes); } else { KRATOS_ERROR << "Nodal mapping requires atleast either conditions or elements to be present in " << mrModelPart.FullName() << ".\n"; @@ -240,21 +251,35 @@ void ExplicitFilterUtils::ExplicitFilterUtils::Update() } template -void ExplicitFilterUtils::CheckField(const ContainerExpression& rContainerExpression) const +void ExplicitFilterUtils::CheckField(const TensorAdaptor& rTensorAdaptor) const { - KRATOS_ERROR_IF(mpFilterRadiusContainer.get() == nullptr) + KRATOS_ERROR_IF(mpFilterRadiusTensorAdaptor.get() == nullptr) << "The filter radius container expression not set. " << "Please set it using SetRadius method.\n\t Filter = " << *this; - KRATOS_ERROR_IF_NOT(rContainerExpression.HasExpression()) - << "Uninitialized container expression given. " - << rContainerExpression; - - KRATOS_ERROR_IF_NOT(&rContainerExpression.GetModelPart() == &mrModelPart) - << "Filter radius container expression model part and filter model part mismatch." - << "\n\tFilter = " << *this - << "\n\tContainerExpression = " << rContainerExpression; + if (std::holds_alternative(rTensorAdaptor.GetContainer())) { + const auto& r_container = *(std::get(rTensorAdaptor.GetContainer())); + KRATOS_ERROR_IF_NOT(&r_container == &mrModelPart.Nodes() || &r_container == &mrModelPart.GetCommunicator().LocalMesh().Nodes()) + << "Filter radius container expression model part and filter model part mismatch." + << "\n\tFilter = " << *this + << "\n\tContainerExpression = " << rTensorAdaptor; + } else if (std::holds_alternative(rTensorAdaptor.GetContainer())) { + const auto& r_container = *(std::get(rTensorAdaptor.GetContainer())); + KRATOS_ERROR_IF_NOT(&r_container == &mrModelPart.Conditions()) + << "Filter radius container expression model part and filter model part mismatch." + << "\n\tFilter = " << *this + << "\n\tContainerExpression = " << rTensorAdaptor; + } else if (std::holds_alternative(rTensorAdaptor.GetContainer())) { + const auto& r_container = *(std::get(rTensorAdaptor.GetContainer())); + KRATOS_ERROR_IF_NOT(&r_container == &mrModelPart.Elements()) + << "Filter radius container expression model part and filter model part mismatch." + << "\n\tFilter = " << *this + << "\n\tContainerExpression = " << rTensorAdaptor; + } else { + KRATOS_ERROR << "Unsupported container type is found in the tensor adaptor. Only supports nodal, condition or elemental tensor adaptors [ tensor adaptor = " + << rTensorAdaptor << " ].\n"; + } KRATOS_ERROR_IF(mpDamping.get() == nullptr) << "Damping method is not set. " @@ -264,29 +289,28 @@ void ExplicitFilterUtils::CheckField(const ContainerExpression template -ContainerExpression ExplicitFilterUtils::GenericForwardFilterField(const ContainerExpression& rContainerExpression) const +TensorAdaptor::Pointer ExplicitFilterUtils::GenericForwardFilterField(const TensorAdaptor& rTensorAdaptor) const { KRATOS_TRY using tls = OptimizationUtils::KDTreeThreadLocalStorage; - CheckField(rContainerExpression); + CheckField(rTensorAdaptor); - const IndexType stride = rContainerExpression.GetItemComponentCount(); - const auto& r_origin_expression = rContainerExpression.GetExpression(); - const auto& r_container = rContainerExpression.GetContainer(); - const auto& r_filter_radius_expression = mpFilterRadiusContainer->GetExpression(); + const auto& r_origin_data_view = rTensorAdaptor.ViewData(); + const auto& r_container = *(std::get(rTensorAdaptor.GetContainer())); + const IndexType stride = rTensorAdaptor.Size() / r_container.size(); + const auto& r_filter_radius_data_view = mpFilterRadiusTensorAdaptor->ViewData(); KRATOS_ERROR_IF_NOT(stride == mpDamping->GetStride()) << "Damping stride and expression stride mismatch. [ damping stride = " << mpDamping->GetStride() << ", expression stride = " << stride << " ].\n"; - ContainerExpression result(*rContainerExpression.pGetModelPart()); - auto p_expression = LiteralFlatExpression::Create(result.GetContainer().size(), rContainerExpression.GetItemShape()); - result.SetExpression(p_expression); + auto p_result_tensor_adaptor = Kratos::make_shared>(rTensorAdaptor); + auto result_data_view = p_result_tensor_adaptor->ViewData(); IndexPartition(r_container.size()).for_each(tls(mMaxNumberOfNeighbors, stride), [&](const IndexType Index, tls& rTLS){ - const double radius = r_filter_radius_expression.Evaluate(Index, Index, 0); + const double radius = r_filter_radius_data_view[Index]; EntityPoint entity_point(*(r_container.begin() + Index), Index); const auto number_of_neighbors = mpSearchTree->SearchInRadius( @@ -304,18 +328,18 @@ ContainerExpression ExplicitFilterUtils::Generic double sum_of_weights = 0.0; ExplicitFilterUtilsHelperUtilities::ComputeWeightForAllNeighbors( sum_of_weights, rTLS.mListOfWeights, *mpKernelFunction, radius, - entity_point, rTLS.mNeighbourEntityPoints, rTLS.mResultingSquaredDistances, number_of_neighbors, this->mpNodalDomainSizeExpression.get()); + entity_point, rTLS.mNeighbourEntityPoints, rTLS.mResultingSquaredDistances, number_of_neighbors, this->mNodalDomainSizes); mpDamping->Apply(rTLS.mListOfDampedWeights, rTLS.mListOfWeights, Index, number_of_neighbors, rTLS.mNeighbourEntityPoints); for (IndexType j = 0; j < stride; ++j) { const auto& r_damped_weights = rTLS.mListOfDampedWeights[j]; - double& current_index_value = *(p_expression->begin() + Index * stride + j); + double& current_index_value = result_data_view[Index * stride + j]; current_index_value = 0.0; for(IndexType neighbour_index = 0 ; neighbour_index < number_of_neighbors; ++neighbour_index) { const IndexType neighbour_id = rTLS.mNeighbourEntityPoints[neighbour_index]->Id(); const double weight = r_damped_weights[neighbour_index] / sum_of_weights; - const double origin_value = r_origin_expression.Evaluate(neighbour_id, neighbour_id * stride, j); + const double origin_value = r_origin_data_view[neighbour_id * stride + j]; current_index_value += weight * origin_value; } } @@ -323,40 +347,39 @@ ContainerExpression ExplicitFilterUtils::Generic KRATOS_INFO_IF("ExplicitFilterUtils", mEchoLevel > 1) << "Computed forward filter field." << std::endl; - return result; + return p_result_tensor_adaptor; KRATOS_CATCH(""); } template template -ContainerExpression ExplicitFilterUtils::GenericBackwardFilterField(const ContainerExpression& rContainerExpression) const +TensorAdaptor::Pointer ExplicitFilterUtils::GenericBackwardFilterField(const TensorAdaptor& rTensorAdaptor) const { KRATOS_TRY using tls = OptimizationUtils::KDTreeThreadLocalStorage; - CheckField(rContainerExpression); + CheckField(rTensorAdaptor); - const IndexType stride = rContainerExpression.GetItemComponentCount(); - const auto& r_origin_expression = rContainerExpression.GetExpression(); - const auto& r_container = rContainerExpression.GetContainer(); - const auto& r_filter_radius_expression = mpFilterRadiusContainer->GetExpression(); + const auto& r_origin_data_view = rTensorAdaptor.ViewData(); + const auto& r_container = *(std::get(rTensorAdaptor.GetContainer())); + const IndexType stride = r_origin_data_view.size() / r_container.size(); + const auto& r_filter_radius_data_view = mpFilterRadiusTensorAdaptor->ViewData(); KRATOS_ERROR_IF_NOT(stride == mpDamping->GetStride()) << "Damping stride and expression stride mismatch. [ damping stride = " << mpDamping->GetStride() << ", expression stride = " << stride << " ].\n"; - ContainerExpression result(*rContainerExpression.pGetModelPart()); - auto p_expression = LiteralFlatExpression::Create(result.GetContainer().size(), rContainerExpression.GetItemShape()); - result.SetExpression(p_expression); + auto p_result_tensor_adaptor = Kratos::make_shared>(rTensorAdaptor); + auto result_data_view = p_result_tensor_adaptor->ViewData(); - IndexPartition(result.GetContainer().size() * stride).for_each([&p_expression](const auto Index) { - *(p_expression->begin() + Index) = 0.0; + IndexPartition(result_data_view.size()).for_each([&result_data_view](const auto Index) { + result_data_view[Index] = 0.0; }); IndexPartition(r_container.size()).for_each(tls(mMaxNumberOfNeighbors, stride), [&](const IndexType Index, tls& rTLS){ - const double radius = r_filter_radius_expression.Evaluate(Index, Index, 0); + const double radius = r_filter_radius_data_view[Index]; EntityPoint entity_point(*(r_container.begin() + Index), Index); const auto number_of_neighbors = mpSearchTree->SearchInRadius( @@ -374,16 +397,17 @@ ContainerExpression ExplicitFilterUtils::Generic double sum_of_weights = 0.0; ExplicitFilterUtilsHelperUtilities::ComputeWeightForAllNeighbors( sum_of_weights, rTLS.mListOfWeights, *mpKernelFunction, radius, - entity_point, rTLS.mNeighbourEntityPoints, rTLS.mResultingSquaredDistances, number_of_neighbors, this->mpNodalDomainSizeExpression.get()); + entity_point, rTLS.mNeighbourEntityPoints, rTLS.mResultingSquaredDistances, number_of_neighbors, this->mNodalDomainSizes); mpDamping->Apply(rTLS.mListOfDampedWeights, rTLS.mListOfWeights, Index, number_of_neighbors, rTLS.mNeighbourEntityPoints); const IndexType current_data_begin = Index * stride; - const double domain_size = TMeshDependencyType::GetDomainSize(entity_point, mpNodalDomainSizeExpression.get()); + const double domain_size = TMeshDependencyType::GetDomainSize(entity_point, mNodalDomainSizes); for (IndexType j = 0; j < stride; ++j) { const auto& r_damped_weights = rTLS.mListOfDampedWeights[j]; - const double origin_value = TMeshDependencyType::Compute(r_origin_expression.Evaluate(Index, current_data_begin, j), domain_size); + const double origin_value = TMeshDependencyType::Compute(r_origin_data_view[current_data_begin + j], domain_size); + // KRATOS_WATCH(origin_value) for(IndexType neighbour_index = 0; neighbour_index < number_of_neighbors; ++neighbour_index) { const double weight = r_damped_weights[neighbour_index] / sum_of_weights; @@ -391,79 +415,80 @@ ContainerExpression ExplicitFilterUtils::Generic const IndexType neighbour_id = rTLS.mNeighbourEntityPoints[neighbour_index]->Id(); const IndexType neighbour_data_begin_index = neighbour_id * stride; - AtomicAdd(*(p_expression->begin() + neighbour_data_begin_index + j), origin_value * weight); + // KRATOS_WATCH(neighbour_id) + // KRATOS_WATCH(weight) + + AtomicAdd(result_data_view[neighbour_data_begin_index + j], origin_value * weight); + double temp = result_data_view[neighbour_data_begin_index + j]; + // std::cout << std::scientific << std::setprecision(18) << "temp:" << temp << std::endl; } } }); KRATOS_INFO_IF("ExplicitFilterUtils", mEchoLevel > 1) << "Computed backward filter field." << std::endl; - return result; + return p_result_tensor_adaptor; KRATOS_CATCH(""); } template template -void ExplicitFilterUtils::GenericGetIntegrationWeights(ContainerExpression& rContainerExpression) const +void ExplicitFilterUtils::GenericGetIntegrationWeights(TensorAdaptor& rTensorAdaptor) const { + CheckField(rTensorAdaptor); - KRATOS_ERROR_IF_NOT(&rContainerExpression.GetModelPart() == &mrModelPart) - << "The given container expression model part and filter model part mismatch."; - - const IndexType stride = rContainerExpression.GetItemComponentCount(); - const auto& r_container = rContainerExpression.GetContainer(); - auto p_expression = LiteralFlatExpression::Create(r_container.GetContainer().size(), rContainerExpression.GetItemShape()); - rContainerExpression.SetExpression(p_expression); + const auto& r_container = *(std::get(rTensorAdaptor.GetContainer())); + const IndexType stride = rTensorAdaptor.Size() / r_container.size(); + auto r_data_view = rTensorAdaptor.ViewData(); IndexPartition(r_container.size()).for_each([&](const IndexType Index){ const EntityPoint entity(*(r_container.begin() + Index), Index); - const auto integration_weight = TMeshDependencyType::GetDomainSize(entity, this->mpNodalDomainSizeExpression.get()); + const auto integration_weight = TMeshDependencyType::GetDomainSize(entity, this->mNodalDomainSizes); const IndexType current_data_begin = Index * stride; for (IndexType j = 0; j < stride; ++j) { - double& current_index_value = *(p_expression->begin() + current_data_begin + j); - current_index_value = integration_weight; + r_data_view[current_data_begin + j] = integration_weight; } }); } template -ContainerExpression ExplicitFilterUtils::ForwardFilterField(const ContainerExpression& rContainerExpression) const +TensorAdaptor::Pointer ExplicitFilterUtils::ForwardFilterField(const TensorAdaptor& rTensorAdaptor) const { if (mNodeCloudMesh) { - return GenericForwardFilterField(rContainerExpression); + return GenericForwardFilterField(rTensorAdaptor); } else { - return GenericForwardFilterField(rContainerExpression); + return GenericForwardFilterField(rTensorAdaptor); } } template -ContainerExpression ExplicitFilterUtils::BackwardFilterField(const ContainerExpression& rContainerExpression) const +TensorAdaptor::Pointer ExplicitFilterUtils::BackwardFilterField(const TensorAdaptor& rTensorAdaptor) const { if (mNodeCloudMesh) { - return GenericBackwardFilterField(rContainerExpression); + return GenericBackwardFilterField(rTensorAdaptor); } else { - return GenericBackwardFilterField(rContainerExpression); + return GenericBackwardFilterField(rTensorAdaptor); } } template -ContainerExpression ExplicitFilterUtils::BackwardFilterIntegratedField(const ContainerExpression& rContainerExpression) const +TensorAdaptor::Pointer ExplicitFilterUtils::BackwardFilterIntegratedField(const TensorAdaptor& rTensorAdaptor) const { if (mNodeCloudMesh) { - return GenericBackwardFilterField(rContainerExpression); + return GenericBackwardFilterField(rTensorAdaptor); } else { - return GenericBackwardFilterField(rContainerExpression); + return GenericBackwardFilterField(rTensorAdaptor); } } template -void ExplicitFilterUtils::GetIntegrationWeights(ContainerExpression& rContainerExpression) const +void ExplicitFilterUtils::GetIntegrationWeights(TensorAdaptor& rTensorAdaptor) const { if (mNodeCloudMesh) { - GenericGetIntegrationWeights(rContainerExpression); + GenericGetIntegrationWeights(rTensorAdaptor); } else { - GenericGetIntegrationWeights(rContainerExpression); + GenericGetIntegrationWeights(rTensorAdaptor); } } @@ -495,7 +520,7 @@ void ExplicitFilterUtils::CalculateMatrix(Matrix& rOutput) const const auto number_of_entities = mEntityPointVector.size(); - const auto& r_filter_radius_expression = mpFilterRadiusContainer->GetExpression(); + const auto r_filter_radius_data_view = mpFilterRadiusTensorAdaptor->ViewData(); if (rOutput.size1 () != number_of_entities || rOutput.size2() != number_of_entities) { rOutput.resize(number_of_entities, number_of_entities, false); @@ -504,7 +529,7 @@ void ExplicitFilterUtils::CalculateMatrix(Matrix& rOutput) const noalias(rOutput) = ZeroMatrix(number_of_entities, number_of_entities); IndexPartition(number_of_entities).for_each(tls(mMaxNumberOfNeighbors, 1), [&](const auto Index, auto& rTLS) { - const double radius = r_filter_radius_expression.Evaluate(Index, Index, 0); + const double radius = r_filter_radius_data_view[Index]; const auto number_of_neighbors = mpSearchTree->SearchInRadius( *mEntityPointVector[Index], @@ -522,7 +547,7 @@ void ExplicitFilterUtils::CalculateMatrix(Matrix& rOutput) const double sum_of_weights = 0.0; ExplicitFilterUtilsHelperUtilities::ComputeWeightForAllNeighbors( sum_of_weights, list_of_weights, *mpKernelFunction, radius, - *mEntityPointVector[Index], rTLS.mNeighbourEntityPoints, rTLS.mResultingSquaredDistances, number_of_neighbors, this->mpNodalDomainSizeExpression.get()); + *mEntityPointVector[Index], rTLS.mNeighbourEntityPoints, rTLS.mResultingSquaredDistances, number_of_neighbors, this->mNodalDomainSizes); double* data_begin = (rOutput.data().begin() + Index * number_of_entities); @@ -536,15 +561,8 @@ void ExplicitFilterUtils::CalculateMatrix(Matrix& rOutput) const } // template instantiations -#define KRATOS_INSTANTIATE_EXPLICIT_FILTER_METHODS(CONTAINER_TYPE) \ - template class ExplicitFilterUtils; \ - template ContainerExpression ExplicitFilterUtils::GenericBackwardFilterField(const ContainerExpression&) const; \ - template ContainerExpression ExplicitFilterUtils::GenericBackwardFilterField(const ContainerExpression&) const; - -KRATOS_INSTANTIATE_EXPLICIT_FILTER_METHODS(ModelPart::NodesContainerType) -KRATOS_INSTANTIATE_EXPLICIT_FILTER_METHODS(ModelPart::ConditionsContainerType) -KRATOS_INSTANTIATE_EXPLICIT_FILTER_METHODS(ModelPart::ElementsContainerType) - -#undef KRATOS_INSTANTIATE_EXPLICIT_FILTER_METHODS +template class ExplicitFilterUtils; +template class ExplicitFilterUtils; +template class ExplicitFilterUtils; } // namespace Kratos \ No newline at end of file diff --git a/applications/OptimizationApplication/custom_utilities/filtering/explicit_filter_utils.h b/applications/OptimizationApplication/custom_utilities/filtering/explicit_filter_utils.h index bdb035253314..b3d47112af95 100644 --- a/applications/OptimizationApplication/custom_utilities/filtering/explicit_filter_utils.h +++ b/applications/OptimizationApplication/custom_utilities/filtering/explicit_filter_utils.h @@ -22,7 +22,7 @@ #include "includes/define.h" #include "includes/model_part.h" #include "spatial_containers/spatial_containers.h" -#include "expression/container_expression.h" +#include "tensor_adaptors/tensor_adaptor.h" // Application includes #include "entity_point.h" @@ -69,14 +69,14 @@ class KRATOS_API(OPTIMIZATION_APPLICATION) ExplicitFilterUtils ///@} ///@name Public operations - void SetRadius(const ContainerExpression& rContainerExpression); + void SetRadius(TensorAdaptor::Pointer pTensorAdaptor); - ContainerExpression GetRadius() const; + TensorAdaptor::Pointer GetRadius() const; void SetDamping(typename ExplicitDamping::Pointer pExplicitDamping); /** - * @brief Updates the internal KD trees or searching neghbours + * @brief Updates the internal KD trees or searching neighbours * */ void Update(); @@ -92,9 +92,9 @@ class KRATOS_API(OPTIMIZATION_APPLICATION) ExplicitFilterUtils * \f] * * @param rContainerExpression mesh-independent update field in control space. - * @return ContainerExpression Filtered/Smoothened mesh-independent update field in physical space + * @return TensorAdaptor::Pointer Filtered/Smoothened mesh-independent update field in physical space */ - ContainerExpression ForwardFilterField(const ContainerExpression& rContainerExpression) const; + TensorAdaptor::Pointer ForwardFilterField(const TensorAdaptor& rTensorAdaptor) const; /** * @brief Filters the given mesh-independent physical space gradients to mesh-independent control space gradients. @@ -102,9 +102,9 @@ class KRATOS_API(OPTIMIZATION_APPLICATION) ExplicitFilterUtils * by using the transpose of the @ref ForwardFilterField method. * * @param rContainerExpression Mesh-independent physical space gradient. - * @return ContainerExpression Mesh-independent control space gradient. + * @return TensorAdaptor::Pointer Mesh-independent control space gradient. */ - ContainerExpression BackwardFilterField(const ContainerExpression& rContainerExpression) const; + TensorAdaptor::Pointer BackwardFilterField(const TensorAdaptor& rTensorAdaptor) const; /** * @brief Filters the given mesh-dependent physical space gradients to mesh-independent control space gradients. @@ -112,14 +112,14 @@ class KRATOS_API(OPTIMIZATION_APPLICATION) ExplicitFilterUtils * by using the transpose of the @ref ForwardFilterField method. * * @param rContainerExpression Mesh-dependent physical space gradient. - * @return ContainerExpression Mesh-independent control space gradient. + * @return TensorAdaptor::Pointer Mesh-independent control space gradient. */ - ContainerExpression BackwardFilterIntegratedField(const ContainerExpression& rContainerExpression) const; + TensorAdaptor::Pointer BackwardFilterIntegratedField(const TensorAdaptor& rTensorAdaptor) const; /** * @brief Get the Integration Weights object */ - void GetIntegrationWeights(ContainerExpression& rContainerExpression) const; + void GetIntegrationWeights(TensorAdaptor& rTensorAdaptor) const; /** * @brief Calculates the filtering matrix used in this filter. @@ -145,11 +145,11 @@ class KRATOS_API(OPTIMIZATION_APPLICATION) ExplicitFilterUtils FilterFunction::UniquePointer mpKernelFunction; - typename ContainerExpression::Pointer mpFilterRadiusContainer; + TensorAdaptor::Pointer mpFilterRadiusTensorAdaptor; typename ExplicitDamping::Pointer mpDamping; - Expression::ConstPointer mpNodalDomainSizeExpression; + std::vector mNodalDomainSizes; EntityPointVector mEntityPointVector; @@ -167,16 +167,16 @@ class KRATOS_API(OPTIMIZATION_APPLICATION) ExplicitFilterUtils ///@name Private operations ///@{ - void CheckField(const ContainerExpression& rContainerExpression) const; + void CheckField(const TensorAdaptor& rTensorAdaptor) const; template - void GenericGetIntegrationWeights(ContainerExpression& rContainerExpression) const; + void GenericGetIntegrationWeights(TensorAdaptor& rTensorAdapto) const; template - ContainerExpression GenericForwardFilterField(const ContainerExpression& rContainerExpression) const; + TensorAdaptor::Pointer GenericForwardFilterField(const TensorAdaptor& rTensorAdaptor) const; template - ContainerExpression GenericBackwardFilterField(const ContainerExpression& rContainerExpression) const; + TensorAdaptor::Pointer GenericBackwardFilterField(const TensorAdaptor& rTensorAdaptor) const; ///@} }; From 62724216b8410cf1b0151e85b0f9247c24140ee2 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 30 Jan 2026 12:40:56 +0100 Subject: [PATCH 019/116] integrated nearest entity update --- ...rated_neareset_entity_explicit_damping.cpp | 25 ++++++++++++------- ...egrated_neareset_entity_explicit_damping.h | 9 +++---- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/applications/OptimizationApplication/custom_utilities/filtering/integrated_neareset_entity_explicit_damping.cpp b/applications/OptimizationApplication/custom_utilities/filtering/integrated_neareset_entity_explicit_damping.cpp index 3468deafeb0f..1b8adf443799 100644 --- a/applications/OptimizationApplication/custom_utilities/filtering/integrated_neareset_entity_explicit_damping.cpp +++ b/applications/OptimizationApplication/custom_utilities/filtering/integrated_neareset_entity_explicit_damping.cpp @@ -16,7 +16,6 @@ // Project includes #include "includes/model_part.h" -#include "expression/literal_flat_expression.h" #include "utilities/model_part_utils.h" // Application includes @@ -67,13 +66,21 @@ IntegratedNearestEntityExplicitDamping::IntegratedNearestEntityE } template -void IntegratedNearestEntityExplicitDamping::SetRadius(const ContainerExpression& rDampingRadiusExpression) +void IntegratedNearestEntityExplicitDamping::SetRadius(TensorAdaptor::Pointer pDampingRadiusTensorAdaptor) { - mpDampingRadius = rDampingRadiusExpression.Clone(); + KRATOS_TRY + + KRATOS_ERROR_IF_NOT(std::holds_alternative(pDampingRadiusTensorAdaptor->GetContainer())) + << "Radius container type and the explicit damping type container mismatch [ " + << "tensor adaptor = " << *pDampingRadiusTensorAdaptor << " ].\n"; + + mpDampingRadius = pDampingRadiusTensorAdaptor; + + KRATOS_CATCH(""); } template -typename ContainerExpression::Pointer IntegratedNearestEntityExplicitDamping::GetRadius() const +TensorAdaptor::Pointer IntegratedNearestEntityExplicitDamping::GetRadius() const { return mpDampingRadius; } @@ -135,7 +142,7 @@ void IntegratedNearestEntityExplicitDamping::IntegratedNearestEn { KRATOS_TRY - const auto radius = mpDampingRadius->GetExpression().Evaluate(Index, Index, 0); + const auto radius = mpDampingRadius->ViewData()[Index]; for (IndexType i_comp = 0; i_comp < this->GetStride(); ++i_comp) { auto& r_damped_weights = rDampedWeights[i_comp]; @@ -166,8 +173,8 @@ void IntegratedNearestEntityExplicitDamping::IntegratedNearestEn using tls = OptimizationUtils::KDTreeThreadLocalStorage; const auto stride = this->GetStride(); - const auto& r_radius_exp = mpDampingRadius->GetExpression(); - const auto& r_container = mpDampingRadius->GetContainer(); + const auto& radius_view = mpDampingRadius->ViewData(); + const auto& r_container = *(std::get(mpDampingRadius->GetContainer())); const auto number_of_entities = r_container.size(); KRATOS_ERROR_IF_NOT(ComponentIndex < stride) @@ -198,8 +205,8 @@ void IntegratedNearestEntityExplicitDamping::IntegratedNearestEn auto& comp_search_tree = *mComponentWiseKDTrees[ComponentIndex]; auto& kernel_function = *mpKernelFunction; - IndexPartition(number_of_entities).for_each(tls(1000, 1), [&rOutput, &r_container, &r_radius_exp, &search_tree, &comp_search_tree, &kernel_function, number_of_entities](const auto Index, auto& rTLS) { - const auto radius = r_radius_exp.Evaluate(Index, Index, 0); + IndexPartition(number_of_entities).for_each(tls(1000, 1), [&rOutput, &r_container, &radius_view, &search_tree, &comp_search_tree, &kernel_function, number_of_entities](const auto Index, auto& rTLS) { + const auto radius = radius_view[Index]; EntityPoint entity_point(*(r_container.begin() + Index), Index); const auto number_of_neighbors = search_tree.SearchInRadius( entity_point, diff --git a/applications/OptimizationApplication/custom_utilities/filtering/integrated_neareset_entity_explicit_damping.h b/applications/OptimizationApplication/custom_utilities/filtering/integrated_neareset_entity_explicit_damping.h index 6dda13a48edb..8db4500a7eb8 100644 --- a/applications/OptimizationApplication/custom_utilities/filtering/integrated_neareset_entity_explicit_damping.h +++ b/applications/OptimizationApplication/custom_utilities/filtering/integrated_neareset_entity_explicit_damping.h @@ -18,8 +18,7 @@ // Project includes #include "containers/model.h" -#include "expression/container_expression.h" -#include "expression/expression.h" +#include "tensor_adaptors/tensor_adaptor.h" #include "includes/define.h" #include "spatial_containers/spatial_containers.h" @@ -72,9 +71,9 @@ class KRATOS_API(OPTIMIZATION_APPLICATION) IntegratedNearestEntityExplicitDampin ///@name Operations ///@{ - void SetRadius(const ContainerExpression& rDampingRadiusExpression) override; + void SetRadius(TensorAdaptor::Pointer pDampingRadiusTensorAdaptor) override; - typename ContainerExpression::Pointer GetRadius() const override; + TensorAdaptor::Pointer GetRadius() const override; IndexType GetStride() const override; @@ -105,7 +104,7 @@ class KRATOS_API(OPTIMIZATION_APPLICATION) IntegratedNearestEntityExplicitDampin DampingFunction::UniquePointer mpKernelFunction; - typename ContainerExpression::Pointer mpDampingRadius; + TensorAdaptor::Pointer mpDampingRadius; std::vector> mComponentWiseDampedModelParts; From 0e07e2abf7261729e3f2b67056a2dc8690c76756 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 30 Jan 2026 12:41:09 +0100 Subject: [PATCH 020/116] undate nearest entity update --- .../neareset_entity_explicit_damping.cpp | 54 +++++++++---------- .../neareset_entity_explicit_damping.h | 11 ++-- 2 files changed, 29 insertions(+), 36 deletions(-) diff --git a/applications/OptimizationApplication/custom_utilities/filtering/neareset_entity_explicit_damping.cpp b/applications/OptimizationApplication/custom_utilities/filtering/neareset_entity_explicit_damping.cpp index d7a66535d6f9..ba193ae2e2b7 100644 --- a/applications/OptimizationApplication/custom_utilities/filtering/neareset_entity_explicit_damping.cpp +++ b/applications/OptimizationApplication/custom_utilities/filtering/neareset_entity_explicit_damping.cpp @@ -15,7 +15,6 @@ // Project includes #include "includes/model_part.h" -#include "expression/literal_flat_expression.h" #include "utilities/model_part_utils.h" // Application includes @@ -60,13 +59,21 @@ NearestEntityExplicitDamping::NearestEntityExplicitDamping( } template -void NearestEntityExplicitDamping::SetRadius(const ContainerExpression& rDampingRadiusExpression) +void NearestEntityExplicitDamping::SetRadius(TensorAdaptor::Pointer pDampingRadiusTensorAdaptor) { - mpDampingRadius = rDampingRadiusExpression.Clone(); + KRATOS_TRY + + KRATOS_ERROR_IF_NOT(std::holds_alternative(pDampingRadiusTensorAdaptor->GetContainer())) + << "Radius container type and the explicit damping type container mismatch [ " + << "tensor adaptor = " << *pDampingRadiusTensorAdaptor << " ].\n"; + + mpDampingRadius = pDampingRadiusTensorAdaptor; + + KRATOS_CATCH(""); } template -typename ContainerExpression::Pointer NearestEntityExplicitDamping::GetRadius() const +TensorAdaptor::Pointer NearestEntityExplicitDamping::GetRadius() const { return mpDampingRadius; } @@ -89,16 +96,10 @@ void NearestEntityExplicitDamping::Update() KRATOS_TRY const auto stride = this->GetStride(); - auto& r_container = mpDampingRadius->GetContainer(); - const auto& r_damping_radius = mpDampingRadius->GetExpression(); - - // first create the output expression with correct required shape - LiteralFlatExpression::Pointer p_output_expression; - if (stride == 1) { - p_output_expression = LiteralFlatExpression::Create(r_container.size(), {}); - } else { - p_output_expression = LiteralFlatExpression::Create(r_container.size(), {stride}); - } + auto& r_container = *(std::get(mpDampingRadius->GetContainer())); + const auto radius_view = mpDampingRadius->ViewData(); + + mDampingCoefficients.resize(radius_view.size(), stride); for (IndexType i_comp = 0; i_comp < stride; ++i_comp) { auto& r_damped_model_parts = mComponentWiseDampedModelParts[i_comp]; @@ -120,8 +121,8 @@ void NearestEntityExplicitDamping::Update() } if (damped_entities.empty()) { - IndexPartition(r_container.size()).for_each([&p_output_expression, stride, i_comp](const auto Index) { - *(p_output_expression->begin() + Index * stride + i_comp) = 1.0; + IndexPartition(r_container.size()).for_each([this, stride, i_comp](const auto Index) { + this->mDampingCoefficients(Index, i_comp) = 1.0; }); } else { // now construct the kd tree @@ -129,22 +130,18 @@ void NearestEntityExplicitDamping::Update() const auto& kernel_function = *mpKernelFunction; // now calculate the damping for each entity - IndexPartition(r_container.size()).for_each([&p_output_expression, &r_container, &p_search_tree, &kernel_function, &r_damping_radius, stride, i_comp](const auto Index){ + IndexPartition(r_container.size()).for_each([this, &r_container, &p_search_tree, &kernel_function, &radius_view, stride, i_comp](const auto Index){ EntityPointType entity_point(*(r_container.begin() + Index), Index); - const auto data_begin_index = Index * stride; - const auto radius = r_damping_radius.Evaluate(Index, Index, 0); + const auto radius = radius_view[Index]; double squared_distance; auto p_nearest_damped_entity_point = p_search_tree->SearchNearestPoint(entity_point, squared_distance); - double& value = *(p_output_expression->begin() + data_begin_index + i_comp); - value = 1.0 - kernel_function.ComputeWeight(radius, std::sqrt(squared_distance)); + this->mDampingCoefficients(Index, i_comp) = 1.0 - kernel_function.ComputeWeight(radius, std::sqrt(squared_distance)); }); } } - mpDampingCoefficients = p_output_expression; - KRATOS_CATCH(""); } @@ -158,12 +155,10 @@ void NearestEntityExplicitDamping::NearestEntityExplicitDamping: { KRATOS_TRY - const auto data_begin_index = Index * this->GetStride(); - for (IndexType i_comp = 0; i_comp < this->GetStride(); ++i_comp) { auto& r_damped_weights = rDampedWeights[i_comp]; for (IndexType i_neighbour = 0; i_neighbour < NumberOfNeighbours; ++i_neighbour) { - r_damped_weights[i_neighbour] = rWeights[i_neighbour] * mpDampingCoefficients->Evaluate(Index, data_begin_index, i_comp); + r_damped_weights[i_neighbour] = rWeights[i_neighbour] * mDampingCoefficients(Index, i_comp); } } @@ -178,8 +173,7 @@ void NearestEntityExplicitDamping::NearestEntityExplicitDamping: KRATOS_TRY const auto stride = this->GetStride(); - const auto& r_expression = *mpDampingCoefficients; - const auto number_of_entities = r_expression.NumberOfEntities(); + const auto number_of_entities = mDampingCoefficients.size1(); KRATOS_ERROR_IF_NOT(ComponentIndex < stride) << "Invalid component index [ component index = " << ComponentIndex @@ -191,8 +185,8 @@ void NearestEntityExplicitDamping::NearestEntityExplicitDamping: rOutput.clear(); - IndexPartition(number_of_entities).for_each([&rOutput, &r_expression, stride, ComponentIndex, number_of_entities](const auto Index) { - *(rOutput.data().begin() + Index * number_of_entities + Index) = r_expression.Evaluate(Index, Index * stride, ComponentIndex); + IndexPartition(number_of_entities).for_each([this, &rOutput, stride, ComponentIndex, number_of_entities](const auto Index) { + *(rOutput.data().begin() + Index * number_of_entities + Index) = this->mDampingCoefficients(Index, ComponentIndex); }); KRATOS_CATCH(""); diff --git a/applications/OptimizationApplication/custom_utilities/filtering/neareset_entity_explicit_damping.h b/applications/OptimizationApplication/custom_utilities/filtering/neareset_entity_explicit_damping.h index d7a2493c4a76..2a6583bcbc88 100644 --- a/applications/OptimizationApplication/custom_utilities/filtering/neareset_entity_explicit_damping.h +++ b/applications/OptimizationApplication/custom_utilities/filtering/neareset_entity_explicit_damping.h @@ -17,8 +17,7 @@ // Project includes #include "containers/model.h" -#include "expression/container_expression.h" -#include "expression/expression.h" +#include "tensor_adaptors/tensor_adaptor.h" #include "includes/define.h" #include "spatial_containers/spatial_containers.h" @@ -71,9 +70,9 @@ class KRATOS_API(OPTIMIZATION_APPLICATION) NearestEntityExplicitDamping: public ///@name Operations ///@{ - void SetRadius(const ContainerExpression& rDampingRadiusExpression) override; + void SetRadius(TensorAdaptor::Pointer pDampingRadiusTensorAdaptor) override; - typename ContainerExpression::Pointer GetRadius() const override; + TensorAdaptor::Pointer GetRadius() const override; IndexType GetStride() const override; @@ -104,9 +103,9 @@ class KRATOS_API(OPTIMIZATION_APPLICATION) NearestEntityExplicitDamping: public FilterFunction::UniquePointer mpKernelFunction; - Expression::ConstPointer mpDampingCoefficients; + Matrix mDampingCoefficients; - typename ContainerExpression::Pointer mpDampingRadius; + TensorAdaptor::Pointer mpDampingRadius; std::vector> mComponentWiseDampedModelParts; From 3dee71b5edba36c958d6481a5b8644b08bb468fc Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 30 Jan 2026 19:44:41 +0100 Subject: [PATCH 021/116] bugfix --- .../custom_utilities/filtering/explicit_filter_utils.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/applications/OptimizationApplication/custom_utilities/filtering/explicit_filter_utils.cpp b/applications/OptimizationApplication/custom_utilities/filtering/explicit_filter_utils.cpp index 953674c64b65..e09469a69ea5 100644 --- a/applications/OptimizationApplication/custom_utilities/filtering/explicit_filter_utils.cpp +++ b/applications/OptimizationApplication/custom_utilities/filtering/explicit_filter_utils.cpp @@ -41,7 +41,8 @@ void GetNodalDomainSizeExpression( { const IndexType number_of_nodes = rNodes.size(); - rNodalDomainSizes.resize(number_of_nodes, 0.0); + rNodalDomainSizes.resize(number_of_nodes); + std::fill(rNodalDomainSizes.begin(), rNodalDomainSizes.end(), 0.0); IndexPartition(rContainer.size()).for_each([&rNodes, &rContainer, &rNodalDomainSizes](const IndexType Index) { const auto& r_geometry = (rContainer.begin() + Index)->GetGeometry(); From 419530010ea37d5854ca2f072f55f9f64db887e7 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 30 Jan 2026 19:45:14 +0100 Subject: [PATCH 022/116] update explicit filter python to TA --- .../filtering/explicit_filter.py | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/applications/OptimizationApplication/python_scripts/filtering/explicit_filter.py b/applications/OptimizationApplication/python_scripts/filtering/explicit_filter.py index 51b297542371..876b2636ccda 100644 --- a/applications/OptimizationApplication/python_scripts/filtering/explicit_filter.py +++ b/applications/OptimizationApplication/python_scripts/filtering/explicit_filter.py @@ -86,7 +86,7 @@ def Update(self) -> None: # now set the filter radius. Can be changed in future to support adaptive radius methods. filter_radius = FilterRadiusFactory(self.model_part, self.data_location, self.parameters["filter_radius_settings"]) self.filter_utils.SetRadius(filter_radius) - self.GetComponentDataView().GetUnBufferedData().SetValue("filter_radius", filter_radius.Clone(), overwrite=True) + self.GetComponentDataView().GetUnBufferedData().SetValue("filter_radius", filter_radius, overwrite=True) # now set the damping stride = max(enumerate(accumulate(self.filter_variable_shape, operator.mul, initial=1)))[1] @@ -105,13 +105,25 @@ def Finalize(self) -> None: pass def ForwardFilterField(self, control_field: ContainerExpressionTypes) -> ContainerExpressionTypes: - return self.filter_utils.ForwardFilterField(control_field) + temp_ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(control_field.GetContainer(), Kratos.DoubleNDData(control_field.Evaluate()), False) + result_ta = self.filter_utils.ForwardFilterField(temp_ta) + result = control_field.Clone() + Kratos.Expression.CArrayExpressionIO.Read(result, result_ta.data) + return result def BackwardFilterField(self, physical_mesh_independent_gradient_field: ContainerExpressionTypes) -> ContainerExpressionTypes: - return self.filter_utils.BackwardFilterField(physical_mesh_independent_gradient_field) + temp_ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(physical_mesh_independent_gradient_field.GetContainer(), Kratos.DoubleNDData(physical_mesh_independent_gradient_field.Evaluate()), False) + result_ta = self.filter_utils.BackwardFilterField(temp_ta) + result = physical_mesh_independent_gradient_field.Clone() + Kratos.Expression.CArrayExpressionIO.Read(result, result_ta.data) + return result def BackwardFilterIntegratedField(self, physical_mesh_dependent_gradient_field: ContainerExpressionTypes) -> ContainerExpressionTypes: - return self.filter_utils.BackwardFilterIntegratedField(physical_mesh_dependent_gradient_field) + temp_ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(physical_mesh_dependent_gradient_field.GetContainer(), Kratos.DoubleNDData(physical_mesh_dependent_gradient_field.Evaluate()), False) + result_ta = self.filter_utils.BackwardFilterIntegratedField(temp_ta) + result = physical_mesh_dependent_gradient_field.Clone() + Kratos.Expression.CArrayExpressionIO.Read(result, result_ta.data) + return result def UnfilterField(self, filtered_field: ContainerExpressionTypes) -> ContainerExpressionTypes: # WARNING: In general explicit VM doesn't need unfiltered field because it works with changes. Hence, it returns zeros and optimization runs correctly. From 6f44f3f54bf74f12ef9f5242c5a14f16c2b42d1b Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 30 Jan 2026 19:45:22 +0100 Subject: [PATCH 023/116] update filter utils to TA --- .../python_scripts/filtering/filter_utils.py | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/applications/OptimizationApplication/python_scripts/filtering/filter_utils.py b/applications/OptimizationApplication/python_scripts/filtering/filter_utils.py index 69dc1ee89951..89fb64f891ce 100644 --- a/applications/OptimizationApplication/python_scripts/filtering/filter_utils.py +++ b/applications/OptimizationApplication/python_scripts/filtering/filter_utils.py @@ -4,7 +4,7 @@ import KratosMultiphysics.OptimizationApplication as KratosOA from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import ContainerExpressionTypes -def FilterRadiusFactory(model_part: Kratos.ModelPart, container_type: Kratos.Globals.DataLocation, filter_radius_settings: Kratos.Parameters) -> ContainerExpressionTypes: +def FilterRadiusFactory(model_part: Kratos.ModelPart, container_type: Kratos.Globals.DataLocation, filter_radius_settings: Kratos.Parameters) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: if not filter_radius_settings.Has("filter_radius_type"): raise RuntimeError(f"\"filter_radius_type\" not specified in the following settings:\n{filter_radius_settings}") @@ -15,9 +15,15 @@ def FilterRadiusFactory(model_part: Kratos.ModelPart, container_type: Kratos.Glo "filter_radius" : 0.2 }""") filter_radius_settings.ValidateAndAssignDefaults(defaults) - filter_radius = GetContainerExpression(model_part, container_type) - Kratos.Expression.LiteralExpressionIO.SetData(filter_radius, filter_radius_settings["filter_radius"].GetDouble()) - return filter_radius + + if container_type == Kratos.Globals.DataLocation.NodeHistorical or container_type == Kratos.Globals.DataLocation.NodeNonHistorical: + return Kratos.TensorAdaptors.DoubleTensorAdaptor(model_part.Nodes, Kratos.DoubleNDData([model_part.NumberOfNodes()], filter_radius_settings["filter_radius"].GetDouble()), copy=False) + elif container_type == Kratos.Globals.DataLocation.Condition: + return Kratos.TensorAdaptors.DoubleTensorAdaptor(model_part.Conditions, Kratos.DoubleNDData([model_part.NumberOfConditions()], filter_radius_settings["filter_radius"].GetDouble()), copy=False) + elif container_type == Kratos.Globals.DataLocation.Element: + return Kratos.TensorAdaptors.DoubleTensorAdaptor(model_part.Elements, Kratos.DoubleNDData([model_part.NumberOfElements()], filter_radius_settings["filter_radius"].GetDouble()), copy=False) + else: + raise RuntimeError(f"Unsupported container_type.") else: raise RuntimeError(f"Unsupported filter_radius_type = \"{filter_radius_type}\".") @@ -48,13 +54,3 @@ def ExplicitFilterDampingFactory(model: Kratos.Model, data_location: Kratos.Glob if damping_type not in damping_types_dict[data_location].keys(): raise RuntimeError(f"Unsupported damping_type = \"{damping_type}\". Followings are supported:\n\t" + "\n\t".join(damping_types_dict[data_location].keys())) return damping_types_dict[data_location][damping_type](model, parameters, stride) - -def GetContainerExpression(model_part: Kratos.ModelPart, container_type: Kratos.Globals.DataLocation) -> ContainerExpressionTypes: - if container_type == Kratos.Globals.DataLocation.NodeHistorical or container_type == Kratos.Globals.DataLocation.NodeNonHistorical: - return Kratos.Expression.NodalExpression(model_part) - elif container_type == Kratos.Globals.DataLocation.Condition: - return Kratos.Expression.ConditionExpression(model_part) - elif container_type == Kratos.Globals.DataLocation.Element: - return Kratos.Expression.ElementExpression(model_part) - else: - raise RuntimeError(f"Unsupported container_type.") From 48b233337b8e2b844b0d4258857d99004569acf8 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 30 Jan 2026 19:45:49 +0100 Subject: [PATCH 024/116] update texplicit filter test to TA --- .../tests/filtering/explicit_filters_tests.py | 74 +++++++++---------- 1 file changed, 33 insertions(+), 41 deletions(-) diff --git a/applications/OptimizationApplication/tests/filtering/explicit_filters_tests.py b/applications/OptimizationApplication/tests/filtering/explicit_filters_tests.py index 7752d989ce18..b6db82f7b260 100644 --- a/applications/OptimizationApplication/tests/filtering/explicit_filters_tests.py +++ b/applications/OptimizationApplication/tests/filtering/explicit_filters_tests.py @@ -53,36 +53,30 @@ def test_IntegratedNearestEntityDamping(self): self.__RunMatrixTest(damping) def __RunConsistencyTest(self, vm_filter: FilterUtilsType, entities: EntityContainerType, model_part: Kratos.ModelPart): + radius_exp = Kratos.TensorAdaptors.DoubleTensorAdaptor(entities, Kratos.DoubleNDData([len(entities)]), copy=False) if isinstance(entities, Kratos.NodesArray): - container_expression_type = Kratos.Expression.NodalExpression damping_type = KratosOA.NearestNodeExplicitDamping elif isinstance(entities, Kratos.ConditionsArray): - container_expression_type = Kratos.Expression.ConditionExpression damping_type = KratosOA.NearestConditionExplicitDamping elif isinstance(entities, Kratos.ElementsArray): - container_expression_type = Kratos.Expression.ElementExpression damping_type = KratosOA.NearestElementExplicitDamping - radius_exp = container_expression_type(model_part) - Kratos.Expression.LiteralExpressionIO.SetData(radius_exp, 2.0) - vm_filter.SetRadius(radius_exp.Clone()) + radius_exp.data[:] = 2.0 + vm_filter.SetRadius(radius_exp) damping = damping_type(self.model, Kratos.Parameters("""{"damping_function_type": "cosine"}"""), 3) - damping.SetRadius(radius_exp.Clone()) + damping.SetRadius(radius_exp) vm_filter.SetDamping(damping) damping.Update() vm_filter.Update() - constant_field_value = Kratos.Array3([2.0, 2.0, 2.0]) - - unfiltered_field = container_expression_type(model_part) - Kratos.Expression.LiteralExpressionIO.SetData(unfiltered_field, constant_field_value) + unfiltered_field = Kratos.TensorAdaptors.DoubleTensorAdaptor(entities, Kratos.DoubleNDData([len(entities), 3], 2.0), copy=False) filtered_data = vm_filter.ForwardFilterField(unfiltered_field) - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(filtered_data), math.sqrt(12 * len(entities)), 12) + self.assertAlmostEqual(numpy.linalg.norm(filtered_data.data), math.sqrt(12 * len(entities)), 12) # check with damping damping = damping_type(self.model, Kratos.Parameters("""{"damping_function_type": "cosine", "damped_model_part_settings": { "test.fixed": [true, true, false] }}"""), 3) - damping.SetRadius(radius_exp.Clone()) + damping.SetRadius(radius_exp) vm_filter.SetDamping(damping) damping.Update() @@ -91,36 +85,34 @@ def __RunConsistencyTest(self, vm_filter: FilterUtilsType, entities: EntityConta physical_sensitivity_numpy_array.append([entity.Id, entity.Id + 1, entity.Id + 2]) physical_sensitivity_numpy_array = numpy.array(physical_sensitivity_numpy_array, dtype=numpy.float64) - physical_sensitivity_field = container_expression_type(model_part) - Kratos.Expression.CArrayExpressionIO.Read(physical_sensitivity_field, physical_sensitivity_numpy_array) - control_update = physical_sensitivity_field * -1.0 + physical_sensitivity_field = Kratos.TensorAdaptors.DoubleTensorAdaptor(entities, Kratos.DoubleNDData(physical_sensitivity_numpy_array), copy=False) + control_update = Kratos.TensorAdaptors.DoubleTensorAdaptor(physical_sensitivity_field) + control_update.data = physical_sensitivity_field.data * -1.0 vm_filter.Update() control_sensitivity_field = vm_filter.BackwardFilterField(physical_sensitivity_field) physical_update = vm_filter.ForwardFilterField(control_update) self.assertAlmostEqual( - Kratos.Expression.Utils.InnerProduct(physical_sensitivity_field, physical_update), - Kratos.Expression.Utils.InnerProduct(control_sensitivity_field, control_update), 9) + numpy.dot(physical_sensitivity_field.data.ravel(), physical_update.data.ravel()), + numpy.dot(control_sensitivity_field.data.ravel(), control_update.data.ravel()), 9) - integration_weights = container_expression_type(model_part) - Kratos.Expression.LiteralExpressionIO.SetData(integration_weights, constant_field_value) + integration_weights = Kratos.TensorAdaptors.DoubleTensorAdaptor(entities, Kratos.DoubleNDData([len(entities), 3], 2.0), copy=False) vm_filter.GetIntegrationWeights(integration_weights) - integrated_physical_sensitivity_field = physical_sensitivity_field * integration_weights + integrated_physical_sensitivity_field = Kratos.TensorAdaptors.DoubleTensorAdaptor(physical_sensitivity_field) + integrated_physical_sensitivity_field.data = physical_sensitivity_field.data * integration_weights.data temp = vm_filter.BackwardFilterIntegratedField(integrated_physical_sensitivity_field) - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(temp - control_sensitivity_field), 0.0, 9) + self.assertAlmostEqual(numpy.linalg.norm(temp.data - control_sensitivity_field.data), 0.0, 9) def __RunMatrixTest(self, damping: DampingType) -> None: model_part = self.model_part vm_filter = KratosOA.NodeExplicitFilterUtils(model_part, "linear", 1000, 0) - radius_exp = Kratos.Expression.NodalExpression(model_part) - Kratos.Expression.LiteralExpressionIO.SetData(radius_exp, 0.7) - vm_filter.SetRadius(radius_exp.Clone()) - + radius_exp = Kratos.TensorAdaptors.DoubleTensorAdaptor(model_part.Nodes, Kratos.DoubleNDData([len(model_part.Nodes)], 0.7), copy=False) + vm_filter.SetRadius(radius_exp) - damping.SetRadius(radius_exp.Clone()) + damping.SetRadius(radius_exp) vm_filter.SetDamping(damping) damping.Update() vm_filter.Update() @@ -130,17 +122,17 @@ def __RunMatrixTest(self, damping: DampingType) -> None: physical_sensitivity_numpy_array.append(entity.Id) physical_sensitivity_numpy_array = numpy.array(physical_sensitivity_numpy_array, dtype=numpy.float64) - physical_sensitivity_field = Kratos.Expression.NodalExpression(model_part) - Kratos.Expression.CArrayExpressionIO.Read(physical_sensitivity_field, physical_sensitivity_numpy_array) - control_update = physical_sensitivity_field * -1.0 + physical_sensitivity_field = Kratos.TensorAdaptors.DoubleTensorAdaptor(model_part.Nodes, Kratos.DoubleNDData(physical_sensitivity_numpy_array), copy=False) + control_update = Kratos.TensorAdaptors.DoubleTensorAdaptor(physical_sensitivity_field) + control_update.data = physical_sensitivity_field.data * -1.0 # compute nodal area Kratos.CalculateNonHistoricalNodalAreaProcess(model_part).Execute() - nodal_area_exp = Kratos.Expression.NodalExpression(model_part) - Kratos.Expression.VariableExpressionIO.Read(nodal_area_exp, Kratos.NODAL_AREA, False) - nodal_area = nodal_area_exp.Evaluate() + nodal_area_ta = Kratos.TensorAdaptors.VariableTensorAdaptor(model_part.Nodes, Kratos.NODAL_AREA) + nodal_area_ta.CollectData() - integrated_physical_sensitivity_field = Kratos.Expression.Utils.Scale(physical_sensitivity_field, nodal_area_exp) + integrated_physical_sensitivity_field = Kratos.TensorAdaptors.DoubleTensorAdaptor(physical_sensitivity_field) + integrated_physical_sensitivity_field.data[:] = physical_sensitivity_field.data[:] * nodal_area_ta.data A = Kratos.Matrix() damping.CalculateMatrix(A, 0) @@ -148,25 +140,25 @@ def __RunMatrixTest(self, damping: DampingType) -> None: vm_filter.CalculateMatrix(A) A = numpy.array(A) - p = control_update.Evaluate() - df_dx = physical_sensitivity_field.Evaluate() + p = control_update.data + df_dx = physical_sensitivity_field.data # test forward filtering x = D @ A @ p - x_vm = vm_filter.ForwardFilterField(control_update).Evaluate() + x_vm = vm_filter.ForwardFilterField(control_update).data self.assertVectorAlmostEqual(x, x_vm) # now test the backward filtering df_dp = A.T @ D @ df_dx - df_dp_vm = vm_filter.BackwardFilterField(physical_sensitivity_field).Evaluate() + df_dp_vm = vm_filter.BackwardFilterField(physical_sensitivity_field).data self.assertVectorAlmostEqual(df_dp, df_dp_vm) self.assertAlmostEqual(df_dx.dot(x), df_dp.dot(p)) # now test the integrated backward filtering - int_df_dx = integrated_physical_sensitivity_field.Evaluate() - df_dp_1 = A.T @ D @ (int_df_dx / nodal_area) - df_dp_1_vm = vm_filter.BackwardFilterIntegratedField(integrated_physical_sensitivity_field).Evaluate() + int_df_dx = integrated_physical_sensitivity_field.data + df_dp_1 = A.T @ D @ (int_df_dx / nodal_area_ta.data) + df_dp_1_vm = vm_filter.BackwardFilterIntegratedField(integrated_physical_sensitivity_field).data self.assertVectorAlmostEqual(df_dp_1, df_dp_vm) self.assertVectorAlmostEqual(df_dp_1, df_dp_1_vm) From 34862e4f8b2551e70706b9868aab8dde55e023f9 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 30 Jan 2026 20:57:39 +0100 Subject: [PATCH 025/116] minor --- .../tests/control/shape/test_vm_shape_control.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/applications/OptimizationApplication/tests/control/shape/test_vm_shape_control.py b/applications/OptimizationApplication/tests/control/shape/test_vm_shape_control.py index f851c7c04900..1a68fc1f7a34 100644 --- a/applications/OptimizationApplication/tests/control/shape/test_vm_shape_control.py +++ b/applications/OptimizationApplication/tests/control/shape/test_vm_shape_control.py @@ -116,10 +116,11 @@ def test_GetPhysicalField(self): self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(shape_field), 20.976176963410882, 10) def test_MapGradient(self): - physical_gradient = self.implicit_shape_control.GetEmptyField() - constant_field_value = Kratos.Array3([1.0, 1.0, 1.0]) - Kratos.Expression.LiteralExpressionIO.SetData(physical_gradient, constant_field_value) - self.explicit_shape_control.filter.filter_utils.GetIntegrationWeights(physical_gradient) + physical_gradient = self.implicit_shape_control.GetEmptyField() + ta_physical_gradient = Kratos.TensorAdaptors.DoubleTensorAdaptor(physical_gradient.GetContainer(), Kratos.DoubleNDData(physical_gradient.Evaluate()), copy=False) + ta_physical_gradient.data[:] = 1.0 + self.explicit_shape_control.filter.filter_utils.GetIntegrationWeights(ta_physical_gradient) + Kratos.Expression.CArrayExpressionIO.Read(physical_gradient, ta_physical_gradient.data) implicit_mapped_gradient = self.implicit_shape_control.MapGradient({KratosOA.SHAPE: physical_gradient}) self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(implicit_mapped_gradient), 27.84296340221239, 10) explicit_mapped_gradient = self.explicit_shape_control.MapGradient({KratosOA.SHAPE: physical_gradient}) From ad5339cbcfaae8f1bcd137c62f693fa71587be72 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Sat, 31 Jan 2026 12:22:11 +0100 Subject: [PATCH 026/116] move TA to submodule --- .../add_custom_tensor_adaptors_to_python.cpp | 47 +++++++++++++++++++ .../add_custom_tensor_adaptors_to_python.h | 28 +++++++++++ .../add_custom_utilities_to_python.cpp | 9 ---- .../linear_strain_energy_response_utils.cpp | 2 +- .../response/mass_response_utils.cpp | 2 +- .../properties_variable_tensor_adaptor.cpp | 0 .../properties_variable_tensor_adaptor.h | 0 7 files changed, 77 insertions(+), 11 deletions(-) create mode 100644 applications/OptimizationApplication/custom_python/add_custom_tensor_adaptors_to_python.cpp create mode 100644 applications/OptimizationApplication/custom_python/add_custom_tensor_adaptors_to_python.h rename applications/OptimizationApplication/custom_utilities/{ => tensor_adaptors}/properties_variable_tensor_adaptor.cpp (100%) rename applications/OptimizationApplication/custom_utilities/{ => tensor_adaptors}/properties_variable_tensor_adaptor.h (100%) diff --git a/applications/OptimizationApplication/custom_python/add_custom_tensor_adaptors_to_python.cpp b/applications/OptimizationApplication/custom_python/add_custom_tensor_adaptors_to_python.cpp new file mode 100644 index 000000000000..6552a312cc9b --- /dev/null +++ b/applications/OptimizationApplication/custom_python/add_custom_tensor_adaptors_to_python.cpp @@ -0,0 +1,47 @@ +// | / | +// ' / __| _` | __| _ \ __| +// . \ | ( | | ( |\__ ` +// _|\_\_| \__,_|\__|\___/ ____/ +// Multi-Physics +// +// License: BSD License +// license: OptimizationApplication/license.txt +// +// Main author: Reza Najian Asl, +// Suneth Warnakulasuriya +// + +// System includes + +// External includes +#include + +// Project includes + +// Application includes +#include "custom_utilities/tensor_adaptors/properties_variable_tensor_adaptor.h" + +// Include base h +#include "add_custom_tensor_adaptors_to_python.h" + +namespace Kratos { +namespace Python { + +void AddCustomTensorAdaptorsToPython(pybind11::module& m) +{ + namespace py = pybind11; + + auto tensor_adaptor_modules = m.def_submodule("TensorAdaptors"); + + py::class_(tensor_adaptor_modules, "PropertiesVariableTensorAdaptor") + .def(py::init(), py::arg("tensor_adaptor"), py::arg("variable"), py::arg("copy") = true) + .def(py::init(), py::arg("container"), py::arg("variable")) + .def(py::init&>(), py::arg("container"), py::arg("variable"), py::arg("data_shape")) + .def(py::init(), py::arg("container"), py::arg("variable")) + .def(py::init&>(), py::arg("container"), py::arg("variable"), py::arg("data_shape")) + ; +} + +} // namespace Python. +} // Namespace Kratos + diff --git a/applications/OptimizationApplication/custom_python/add_custom_tensor_adaptors_to_python.h b/applications/OptimizationApplication/custom_python/add_custom_tensor_adaptors_to_python.h new file mode 100644 index 000000000000..ca3080b9dcfc --- /dev/null +++ b/applications/OptimizationApplication/custom_python/add_custom_tensor_adaptors_to_python.h @@ -0,0 +1,28 @@ +// | / | +// ' / __| _` | __| _ \ __| +// . \ | ( | | ( |\__ ` +// _|\_\_| \__,_|\__|\___/ ____/ +// Multi-Physics +// +// License: BSD License +// license: OptimizationApplication/license.txt +// +// Main author: Reza Najian Asl +// + +#pragma once + +// System includes + +// External includes + +// Project includes +#include "includes/define_python.h" + +namespace Kratos { +namespace Python { + +void AddCustomTensorAdaptorsToPython(pybind11::module& m); + +} // namespace Python. +} // namespace Kratos. diff --git a/applications/OptimizationApplication/custom_python/add_custom_utilities_to_python.cpp b/applications/OptimizationApplication/custom_python/add_custom_utilities_to_python.cpp index c60275f329cb..a775dcb27651 100644 --- a/applications/OptimizationApplication/custom_python/add_custom_utilities_to_python.cpp +++ b/applications/OptimizationApplication/custom_python/add_custom_utilities_to_python.cpp @@ -29,7 +29,6 @@ #include "custom_utilities/implicit_filter_utils.h" #include "custom_utilities/optimization_utils.h" #include "custom_utilities/properties_variable_expression_io.h" -#include "custom_utilities/properties_variable_tensor_adaptor.h" // Include base h #include "add_custom_response_utilities_to_python.h" @@ -380,14 +379,6 @@ void AddCustomUtilitiesToPython(pybind11::module& m) py::arg("variable"), py::arg("data_location")) ; - - py::class_(m, "PropertiesVariableTensorAdaptor") - .def(py::init(), py::arg("tensor_adaptor"), py::arg("variable"), py::arg("copy") = true) - .def(py::init(), py::arg("container"), py::arg("variable")) - .def(py::init&>(), py::arg("container"), py::arg("variable"), py::arg("data_shape")) - .def(py::init(), py::arg("container"), py::arg("variable")) - .def(py::init&>(), py::arg("container"), py::arg("variable"), py::arg("data_shape")) - ; } } // namespace Python. diff --git a/applications/OptimizationApplication/custom_utilities/response/linear_strain_energy_response_utils.cpp b/applications/OptimizationApplication/custom_utilities/response/linear_strain_energy_response_utils.cpp index e2fff7412269..16cc73b1a2d1 100644 --- a/applications/OptimizationApplication/custom_utilities/response/linear_strain_energy_response_utils.cpp +++ b/applications/OptimizationApplication/custom_utilities/response/linear_strain_energy_response_utils.cpp @@ -28,7 +28,7 @@ // Application includes #include "tensor_adaptors/variable_tensor_adaptor.h" -#include "custom_utilities/properties_variable_tensor_adaptor.h" +#include "custom_utilities/tensor_adaptors/properties_variable_tensor_adaptor.h" #include "optimization_application_variables.h" // Include base h diff --git a/applications/OptimizationApplication/custom_utilities/response/mass_response_utils.cpp b/applications/OptimizationApplication/custom_utilities/response/mass_response_utils.cpp index 8860198c9eb2..a8dd4c95592e 100644 --- a/applications/OptimizationApplication/custom_utilities/response/mass_response_utils.cpp +++ b/applications/OptimizationApplication/custom_utilities/response/mass_response_utils.cpp @@ -27,7 +27,7 @@ // Application includes #include "custom_utilities/optimization_utils.h" -#include "custom_utilities/properties_variable_tensor_adaptor.h" +#include "custom_utilities/tensor_adaptors/properties_variable_tensor_adaptor.h" #include "optimization_application_variables.h" // Include base h diff --git a/applications/OptimizationApplication/custom_utilities/properties_variable_tensor_adaptor.cpp b/applications/OptimizationApplication/custom_utilities/tensor_adaptors/properties_variable_tensor_adaptor.cpp similarity index 100% rename from applications/OptimizationApplication/custom_utilities/properties_variable_tensor_adaptor.cpp rename to applications/OptimizationApplication/custom_utilities/tensor_adaptors/properties_variable_tensor_adaptor.cpp diff --git a/applications/OptimizationApplication/custom_utilities/properties_variable_tensor_adaptor.h b/applications/OptimizationApplication/custom_utilities/tensor_adaptors/properties_variable_tensor_adaptor.h similarity index 100% rename from applications/OptimizationApplication/custom_utilities/properties_variable_tensor_adaptor.h rename to applications/OptimizationApplication/custom_utilities/tensor_adaptors/properties_variable_tensor_adaptor.h From e4e9e8905a8266c2b7d373b98de6a953699afea3 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Sat, 31 Jan 2026 13:14:33 +0100 Subject: [PATCH 027/116] adding nodal neighour count TA --- .../add_custom_tensor_adaptors_to_python.cpp | 8 ++ .../nodal_neighbour_count_tensor_adaptor.cpp | 104 +++++++++++++++ .../nodal_neighbour_count_tensor_adaptor.h | 118 ++++++++++++++++++ 3 files changed, 230 insertions(+) create mode 100644 applications/OptimizationApplication/custom_utilities/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.cpp create mode 100644 applications/OptimizationApplication/custom_utilities/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.h diff --git a/applications/OptimizationApplication/custom_python/add_custom_tensor_adaptors_to_python.cpp b/applications/OptimizationApplication/custom_python/add_custom_tensor_adaptors_to_python.cpp index 6552a312cc9b..adc2b7193b6b 100644 --- a/applications/OptimizationApplication/custom_python/add_custom_tensor_adaptors_to_python.cpp +++ b/applications/OptimizationApplication/custom_python/add_custom_tensor_adaptors_to_python.cpp @@ -20,6 +20,7 @@ // Application includes #include "custom_utilities/tensor_adaptors/properties_variable_tensor_adaptor.h" +#include "custom_utilities/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.h" // Include base h #include "add_custom_tensor_adaptors_to_python.h" @@ -40,6 +41,13 @@ void AddCustomTensorAdaptorsToPython(pybind11::module& m) .def(py::init(), py::arg("container"), py::arg("variable")) .def(py::init&>(), py::arg("container"), py::arg("variable"), py::arg("data_shape")) ; + + py::class_(tensor_adaptor_modules, "NodalNeighbourCountTensorAdaptor") + .def(py::init(), py::arg("tensor_adaptor"), py::arg("entity_container"), py::arg("copy") = true) + .def(py::init(), py::arg("tensor_adaptor"), py::arg("entity_container"), py::arg("copy") = true) + .def(py::init(), py::arg("nodes_container"), py::arg("entity_container")) + .def(py::init(), py::arg("nodes_container"), py::arg("entity_container")) + ; } } // namespace Python. diff --git a/applications/OptimizationApplication/custom_utilities/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.cpp b/applications/OptimizationApplication/custom_utilities/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.cpp new file mode 100644 index 000000000000..0f0f4d0d17a2 --- /dev/null +++ b/applications/OptimizationApplication/custom_utilities/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.cpp @@ -0,0 +1,104 @@ +// | / | +// ' / __| _` | __| _ \ __| +// . \ | ( | | ( |\__ ` +// _|\_\_| \__,_|\__|\___/ ____/ +// Multi-Physics +// +// License: BSD License +// Kratos default license: kratos/license.txt +// +// Main authors: Suneth Warnakulasuriya +// + +// System includes +#include + +// External includes + +// Project includes +#include "utilities/atomic_utilities.h" +#include "utilities/data_type_traits.h" + +// Include base h +#include "nodal_neighbour_count_tensor_adaptor.h" + +namespace Kratos { + +template +NodalNeighbourCountTensorAdaptor::NodalNeighbourCountTensorAdaptor( + ModelPart::NodesContainerType::Pointer pNodes, + TContainerPointerType pEntityContainer) + : mpEntityContainer(pEntityContainer) +{ + this->mpContainer = pNodes; + this->mpStorage = Kratos::make_shared(DenseVector(1, pNodes->size())); +} + +template +NodalNeighbourCountTensorAdaptor::NodalNeighbourCountTensorAdaptor( + const TensorAdaptor& rOther, + TContainerPointerType pEntityContainer, + const bool Copy) + : BaseType(rOther, Copy), + mpEntityContainer(pEntityContainer) +{ + KRATOS_TRY + + KRATOS_ERROR_IF_NOT(std::holds_alternative(rOther.GetContainer())) + << "NodalNeighbourCountTensorAdaptor can only be used with tensor data having nodal containers. " + << "[ tensor adaptor = " << rOther << " ].\n"; + + const auto& shape = rOther.Shape(); + KRATOS_ERROR_IF(shape.size() != 1 || shape[0] != this->Size()) + << "NodalNeighbourCountTensorAdaptor needs to have tensor data with shape [n, 1] where n being number of nodes." + << "[ tensor adaptor shape = " << rOther.Shape() << ", tensor adaptor = " << rOther << " ].\n"; + + KRATOS_CATCH(""); +} + +void NodalNeighbourCountTensorAdaptor::CollectData() +{ + KRATOS_TRY + + auto& r_nodes = *std::get(this->GetContainer()); + auto data_view = this->ViewData(); + + std::unordered_map id_index_map; + for (IndexType i = 0; i < r_nodes.size(); ++i) { + data_view[i] = 0; + id_index_map[(r_nodes.begin() + i)->Id()] = i; + } + + std::visit([&data_view, &id_index_map](auto pContainer){ + block_for_each(*pContainer, [&data_view, &id_index_map](const auto& rEntity) { + for (const auto& r_node : rEntity.GetGeometry()) { + AtomicAdd(data_view[id_index_map[r_node.Id()]], 1); + } + }); + }, mpEntityContainer); + + KRATOS_CATCH(""); +} + +void NodalNeighbourCountTensorAdaptor::StoreData() +{ + KRATOS_ERROR << "StoreData method is not implemented."; +} + +std::string NodalNeighbourCountTensorAdaptor::Info() const +{ + std::stringstream info; + info << "NodalNeighbourCountTensorAdaptor:"; + std::visit([&info](auto pContainer) { + info << " number of " << ModelPart::Container>::GetEntityName() << " = " << pContainer->size(); + }, this->mpEntityContainer); + info << ", " << BaseType::Info(); + return info.str(); +} + +template KRATOS_API(OPTIMIZATION_APPLICATION) NodalNeighbourCountTensorAdaptor::NodalNeighbourCountTensorAdaptor(ModelPart::NodesContainerType::Pointer, ModelPart::ConditionsContainerType::Pointer); +template KRATOS_API(OPTIMIZATION_APPLICATION) NodalNeighbourCountTensorAdaptor::NodalNeighbourCountTensorAdaptor(ModelPart::NodesContainerType::Pointer, ModelPart::ElementsContainerType::Pointer); +template KRATOS_API(OPTIMIZATION_APPLICATION) NodalNeighbourCountTensorAdaptor::NodalNeighbourCountTensorAdaptor(const TensorAdaptor&, ModelPart::ConditionsContainerType::Pointer, const bool); +template KRATOS_API(OPTIMIZATION_APPLICATION) NodalNeighbourCountTensorAdaptor::NodalNeighbourCountTensorAdaptor(const TensorAdaptor&, ModelPart::ElementsContainerType::Pointer, const bool); + +} // namespace Kratos \ No newline at end of file diff --git a/applications/OptimizationApplication/custom_utilities/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.h b/applications/OptimizationApplication/custom_utilities/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.h new file mode 100644 index 000000000000..7a3c1aad3a02 --- /dev/null +++ b/applications/OptimizationApplication/custom_utilities/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.h @@ -0,0 +1,118 @@ +// | / | +// ' / __| _` | __| _ \ __| +// . \ | ( | | ( |\__ ` +// _|\_\_| \__,_|\__|\___/ ____/ +// Multi-Physics +// +// License: BSD License +// Kratos default license: kratos/license.txt +// +// Main authors: Suneth Warnakulasuriya +// + +#pragma once + +// System includes +#include + +// External includes + +// Project includes +#include "includes/model_part.h" +#include "tensor_adaptors/tensor_adaptor.h" + +namespace Kratos { + +///@name Kratos Classes +///@{ + +/** + * @class NodalNeighbourCountTensorAdaptor + * @ingroup TensorAdaptors + * @brief Adaptor class for calculating neighbour entities for nodes. + * + * @details This class provides an interface to calculate neighbour entities ( @p pEntityContainer i.e. conditions / elements) for a given specific + * @p pNodes. tensor data associated with Kratos entities' property variables. This @ref TensorAdaptor only implements + * the @ref CollectData method. + * + * @section NodalNeighbourCountTensorAdaptor_supported_container Supported entity container types + * - @ref ModelPart::ConditionsContainerType + * - @ref ModelPart::ElementsContainerType + * + * @section NodalNeighbourCountTensorAdaptor_usage Usage + * - Use @ref Check to verify that the variable exists and they are holding unique memory locations in the entities' properties before collecting/storing data. + * - Use @ref CollectData to fill internal data with the number of neighbouring entities. + * + * @author Suneth Warnakulasuriya + * @see @ref TensorAdaptor Base class. + */ +class KRATOS_API(OPTIMIZATION_APPLICATION) NodalNeighbourCountTensorAdaptor: public TensorAdaptor { +public: + + ///@name Type definitions + ///@{ + + KRATOS_CLASS_POINTER_DEFINITION(NodalNeighbourCountTensorAdaptor); + + using BaseType = TensorAdaptor; + + ///@} + ///@name Life cycle + ///@{ + + template + NodalNeighbourCountTensorAdaptor( + ModelPart::NodesContainerType::Pointer pNodes, + TContainerPointerType pEntityContainer); + + template + NodalNeighbourCountTensorAdaptor( + const TensorAdaptor& rOther, + TContainerPointerType pEntityContainer, + const bool Copy = true); + + // Destructor + ~NodalNeighbourCountTensorAdaptor() override = default; + + ///@} + ///@name Public operations + ///@{ + + /** + * @brief Fill the internal data from Kratos data structures's properties + * @details This will fill the internal data from Kratos data structures's properties. It is advised to call + * at least once the Check method to ensure there won't be any errors if the + * variable is not present in the entities' properties. This will return Variable::Zero() + * values for all the entities when collecting if the variable is not set before. + */ + void CollectData() override; + + /** + * @brief Store internal data to the given container's properties. + * @details This method is designed to store data even if the variable is not already available in the + * entities' properties. If it is not present in the entities' properties, then a correctly shaped zero valued value + * will be set and then their relevant components will be overwritten by this method. + * + * @warning If the entities' properties are not unique for each entity, this will result in a race condition. + */ + void StoreData() override; + + ///@} + ///@name Input and output + ///@{ + + std::string Info() const override; + + ///@} + +private: + ///@name Private member variables + ///@{ + + std::variant mpEntityContainer; + + ///@} +}; + +/// @} +} // namespace Kratos \ No newline at end of file From c002b29302e9bc81640fc4c2a769ebbaab924e8b Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Sat, 31 Jan 2026 13:24:42 +0100 Subject: [PATCH 028/116] minor error fix --- .../nodal_neighbour_count_tensor_adaptor.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/applications/OptimizationApplication/custom_utilities/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.cpp b/applications/OptimizationApplication/custom_utilities/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.cpp index 0f0f4d0d17a2..fd51dd735703 100644 --- a/applications/OptimizationApplication/custom_utilities/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.cpp +++ b/applications/OptimizationApplication/custom_utilities/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.cpp @@ -70,9 +70,17 @@ void NodalNeighbourCountTensorAdaptor::CollectData() } std::visit([&data_view, &id_index_map](auto pContainer){ + using container_type = BareType; block_for_each(*pContainer, [&data_view, &id_index_map](const auto& rEntity) { for (const auto& r_node : rEntity.GetGeometry()) { - AtomicAdd(data_view[id_index_map[r_node.Id()]], 1); + auto itr = id_index_map.find(r_node.Id()); + + KRATOS_ERROR_IF(itr == id_index_map.end()) + << "The node with id " << r_node.Id() << " in the " + << ModelPart::Container::GetEntityName() << " with id " << rEntity.Id() + << " is not found in the nodes list."; + + AtomicAdd(data_view[itr->second], 1); } }); }, mpEntityContainer); From 832326dd6756df346892e59828bdb9efe1806e9e Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Mon, 2 Feb 2026 07:46:06 +0100 Subject: [PATCH 029/116] adding nodal_neighbour ta --- .../nodal_neighbour_count_tensor_adaptor.cpp | 8 ++++---- .../nodal_neighbour_count_tensor_adaptor.h | 18 ++++++------------ 2 files changed, 10 insertions(+), 16 deletions(-) rename {applications/OptimizationApplication/custom_utilities => kratos}/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.cpp (82%) rename {applications/OptimizationApplication/custom_utilities => kratos}/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.h (71%) diff --git a/applications/OptimizationApplication/custom_utilities/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.cpp b/kratos/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.cpp similarity index 82% rename from applications/OptimizationApplication/custom_utilities/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.cpp rename to kratos/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.cpp index fd51dd735703..409c65ba3770 100644 --- a/applications/OptimizationApplication/custom_utilities/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.cpp +++ b/kratos/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.cpp @@ -104,9 +104,9 @@ std::string NodalNeighbourCountTensorAdaptor::Info() const return info.str(); } -template KRATOS_API(OPTIMIZATION_APPLICATION) NodalNeighbourCountTensorAdaptor::NodalNeighbourCountTensorAdaptor(ModelPart::NodesContainerType::Pointer, ModelPart::ConditionsContainerType::Pointer); -template KRATOS_API(OPTIMIZATION_APPLICATION) NodalNeighbourCountTensorAdaptor::NodalNeighbourCountTensorAdaptor(ModelPart::NodesContainerType::Pointer, ModelPart::ElementsContainerType::Pointer); -template KRATOS_API(OPTIMIZATION_APPLICATION) NodalNeighbourCountTensorAdaptor::NodalNeighbourCountTensorAdaptor(const TensorAdaptor&, ModelPart::ConditionsContainerType::Pointer, const bool); -template KRATOS_API(OPTIMIZATION_APPLICATION) NodalNeighbourCountTensorAdaptor::NodalNeighbourCountTensorAdaptor(const TensorAdaptor&, ModelPart::ElementsContainerType::Pointer, const bool); +template KRATOS_API(KRATOS_CORE) NodalNeighbourCountTensorAdaptor::NodalNeighbourCountTensorAdaptor(ModelPart::NodesContainerType::Pointer, ModelPart::ConditionsContainerType::Pointer); +template KRATOS_API(KRATOS_CORE) NodalNeighbourCountTensorAdaptor::NodalNeighbourCountTensorAdaptor(ModelPart::NodesContainerType::Pointer, ModelPart::ElementsContainerType::Pointer); +template KRATOS_API(KRATOS_CORE) NodalNeighbourCountTensorAdaptor::NodalNeighbourCountTensorAdaptor(const TensorAdaptor&, ModelPart::ConditionsContainerType::Pointer, const bool); +template KRATOS_API(KRATOS_CORE) NodalNeighbourCountTensorAdaptor::NodalNeighbourCountTensorAdaptor(const TensorAdaptor&, ModelPart::ElementsContainerType::Pointer, const bool); } // namespace Kratos \ No newline at end of file diff --git a/applications/OptimizationApplication/custom_utilities/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.h b/kratos/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.h similarity index 71% rename from applications/OptimizationApplication/custom_utilities/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.h rename to kratos/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.h index 7a3c1aad3a02..8079f8dc1c01 100644 --- a/applications/OptimizationApplication/custom_utilities/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.h +++ b/kratos/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.h @@ -46,7 +46,7 @@ namespace Kratos { * @author Suneth Warnakulasuriya * @see @ref TensorAdaptor Base class. */ -class KRATOS_API(OPTIMIZATION_APPLICATION) NodalNeighbourCountTensorAdaptor: public TensorAdaptor { +class KRATOS_API(KRATOS_CORE) NodalNeighbourCountTensorAdaptor: public TensorAdaptor { public: ///@name Type definitions @@ -79,21 +79,15 @@ class KRATOS_API(OPTIMIZATION_APPLICATION) NodalNeighbourCountTensorAdaptor: pub ///@{ /** - * @brief Fill the internal data from Kratos data structures's properties - * @details This will fill the internal data from Kratos data structures's properties. It is advised to call - * at least once the Check method to ensure there won't be any errors if the - * variable is not present in the entities' properties. This will return Variable::Zero() - * values for all the entities when collecting if the variable is not set before. + * @brief Fill the internal data with number of neightour entities of nodes + * @details This will fill the internal data for each node with its available number of entities (i.e. conditions / elements). + * @throws std::runtime_error if there is an entity having a node with id which is not present in the provided @p pNodes when this object is constructed. */ void CollectData() override; /** - * @brief Store internal data to the given container's properties. - * @details This method is designed to store data even if the variable is not already available in the - * entities' properties. If it is not present in the entities' properties, then a correctly shaped zero valued value - * will be set and then their relevant components will be overwritten by this method. - * - * @warning If the entities' properties are not unique for each entity, this will result in a race condition. + * @brief Does not do anything + * @throws std::runtime_error always. */ void StoreData() override; From 0e2649a4fd0b102b0eea2a21274b10f8cc725840 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Mon, 2 Feb 2026 07:46:22 +0100 Subject: [PATCH 030/116] exposing to python --- .../add_custom_tensor_adaptors_to_python.cpp | 8 -------- kratos/python/add_tensor_adaptors_to_python.cpp | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/applications/OptimizationApplication/custom_python/add_custom_tensor_adaptors_to_python.cpp b/applications/OptimizationApplication/custom_python/add_custom_tensor_adaptors_to_python.cpp index adc2b7193b6b..6552a312cc9b 100644 --- a/applications/OptimizationApplication/custom_python/add_custom_tensor_adaptors_to_python.cpp +++ b/applications/OptimizationApplication/custom_python/add_custom_tensor_adaptors_to_python.cpp @@ -20,7 +20,6 @@ // Application includes #include "custom_utilities/tensor_adaptors/properties_variable_tensor_adaptor.h" -#include "custom_utilities/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.h" // Include base h #include "add_custom_tensor_adaptors_to_python.h" @@ -41,13 +40,6 @@ void AddCustomTensorAdaptorsToPython(pybind11::module& m) .def(py::init(), py::arg("container"), py::arg("variable")) .def(py::init&>(), py::arg("container"), py::arg("variable"), py::arg("data_shape")) ; - - py::class_(tensor_adaptor_modules, "NodalNeighbourCountTensorAdaptor") - .def(py::init(), py::arg("tensor_adaptor"), py::arg("entity_container"), py::arg("copy") = true) - .def(py::init(), py::arg("tensor_adaptor"), py::arg("entity_container"), py::arg("copy") = true) - .def(py::init(), py::arg("nodes_container"), py::arg("entity_container")) - .def(py::init(), py::arg("nodes_container"), py::arg("entity_container")) - ; } } // namespace Python. diff --git a/kratos/python/add_tensor_adaptors_to_python.cpp b/kratos/python/add_tensor_adaptors_to_python.cpp index a3396b3efe12..8cf8865b2b42 100644 --- a/kratos/python/add_tensor_adaptors_to_python.cpp +++ b/kratos/python/add_tensor_adaptors_to_python.cpp @@ -36,6 +36,7 @@ #include "tensor_adaptors/geometries_tensor_adaptor.h" #include "tensor_adaptors/tensor_adaptor.h" #include "tensor_adaptors/variable_tensor_adaptor.h" +#include "tensor_adaptors/nodal_neighbour_count_tensor_adaptor.h" // Include base h #include "add_tensor_adaptors_to_python.h" @@ -337,6 +338,19 @@ void AddTensorAdaptorsToPython(pybind11::module &m) { .def(py::init(), py::arg("tensor_adaptor"), py::arg("copy") = true); + + py::class_( + tensor_adaptor_sub_module, "NodalNeighbourCountTensorAdaptor") + .def(py::init(), + py::arg("tensor_adaptor"), py::arg("entity_container"), py::arg("copy") = true) + .def(py::init(), + py::arg("tensor_adaptor"), py::arg("entity_container"), py::arg("copy") = true) + .def(py::init(), + py::arg("nodes_container"), py::arg("entity_container")) + .def(py::init(), + py::arg("nodes_container"), py::arg("entity_container")); } } // namespace Kratos::Python. \ No newline at end of file From a1d9a8ec028cd8ab82dfb5418680ae62d97c277a Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Mon, 2 Feb 2026 07:46:28 +0100 Subject: [PATCH 031/116] adding unit tests --- kratos/tests/test_tensor_adaptors.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/kratos/tests/test_tensor_adaptors.py b/kratos/tests/test_tensor_adaptors.py index bb9ed24c7fa5..2d7df880f067 100644 --- a/kratos/tests/test_tensor_adaptors.py +++ b/kratos/tests/test_tensor_adaptors.py @@ -563,6 +563,34 @@ def test_CombinedTensorAdaptorCopy(self): ref_combined_ta.data *= 3.0 self.assertAlmostEqual(numpy.linalg.norm(ref_combined_ta.data - combined_ta.data), 0.0) + def test_NodalNeighboursTensorAdaptorCondition(self): + ta = Kratos.TensorAdaptors.NodalNeighbourCountTensorAdaptor(self.model_part.Nodes, self.model_part.Conditions) + ta.Check() + ta.CollectData() + + for i, v in enumerate(ta.data): + if (i != 0 or i != ta.data.size - 1): + self.assertEqual(v, 2) + else: + self.assertEqual(v, 1) + + with self.assertRaises(RuntimeError): + ta.StoreData() + + def test_NodalNeighboursTensorAdaptorElement(self): + ta = Kratos.TensorAdaptors.NodalNeighbourCountTensorAdaptor(self.model_part.Nodes, self.model_part.Elements) + ta.Check() + ta.CollectData() + + for i, v in enumerate(ta.data): + if (i != 0 or i != ta.data.size - 1): + self.assertEqual(v, 2) + else: + self.assertEqual(v, 1) + + with self.assertRaises(RuntimeError): + ta.StoreData() + def __TestCopyTensorAdaptor(self, tensor_adaptor_type, value_getter): var_ta_orig = tensor_adaptor_type(self.model_part.Nodes, Kratos.VELOCITY, data_shape=[2]) var_ta_orig.Check() From 648e818286b1f789f420cffd8c5682c0b018b1ac Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Mon, 2 Feb 2026 08:38:44 +0100 Subject: [PATCH 032/116] minor --- .../custom_python/optimization_python_application.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/applications/OptimizationApplication/custom_python/optimization_python_application.cpp b/applications/OptimizationApplication/custom_python/optimization_python_application.cpp index f0d61ff3e385..b9e7e901e1bd 100644 --- a/applications/OptimizationApplication/custom_python/optimization_python_application.cpp +++ b/applications/OptimizationApplication/custom_python/optimization_python_application.cpp @@ -33,6 +33,7 @@ #include "custom_python/add_custom_constitutive_laws_to_python.h" #include "custom_python/add_custom_filters_to_python.h" #include "custom_python/add_custom_control_utilities_to_python.h" +#include "custom_python/add_custom_tensor_adaptors_to_python.h" // ============================================================================== @@ -53,6 +54,7 @@ PYBIND11_MODULE(KratosOptimizationApplication, m) AddCustomUtilitiesToPython(m); AddCustomConstitutiveLawsToPython(m); AddCustomFiltersToPython(m); + AddCustomTensorAdaptorsToPython(m); auto response_utils = m.def_submodule("ResponseUtils"); AddCustomResponseUtilitiesToPython(response_utils); @@ -60,6 +62,7 @@ PYBIND11_MODULE(KratosOptimizationApplication, m) auto control_utils = m.def_submodule("ControlUtils"); AddCustomControlUtilitiesToPython(control_utils); + //registering variables in python // Optimization variables From aa0c9674a1c1fec82d2e90bc1f5d1586ec9851a7 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Mon, 2 Feb 2026 09:40:30 +0100 Subject: [PATCH 033/116] add design var projection unit tests --- .../utilities/opt_projection.py | 3 +- .../tests/test_design_variable_projection.py | 188 ++++++++++++++++++ 2 files changed, 189 insertions(+), 2 deletions(-) create mode 100644 applications/OptimizationApplication/tests/test_design_variable_projection.py diff --git a/applications/OptimizationApplication/python_scripts/utilities/opt_projection.py b/applications/OptimizationApplication/python_scripts/utilities/opt_projection.py index eaca8e58c123..4ce89009667f 100644 --- a/applications/OptimizationApplication/python_scripts/utilities/opt_projection.py +++ b/applications/OptimizationApplication/python_scripts/utilities/opt_projection.py @@ -72,8 +72,7 @@ def Update(self) -> None: class IdentityDesignVariableProjection(DesignVariableProjection): def __init__(self, parameters: Kratos.Parameters, _): default_settings = Kratos.Parameters("""{ - "type" : "identity_projection", - "extrapolate": "false" + "type" : "identity_projection" }""") parameters.ValidateAndAssignDefaults(default_settings) pass diff --git a/applications/OptimizationApplication/tests/test_design_variable_projection.py b/applications/OptimizationApplication/tests/test_design_variable_projection.py new file mode 100644 index 000000000000..e179f88ca357 --- /dev/null +++ b/applications/OptimizationApplication/tests/test_design_variable_projection.py @@ -0,0 +1,188 @@ +import numpy +import KratosMultiphysics as Kratos +import KratosMultiphysics.KratosUnittest as kratos_unittest + +from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem +from KratosMultiphysics.OptimizationApplication.utilities.opt_projection import CreateProjection + +class TestIdentityDesignVariableProjection(kratos_unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.model = Kratos.Model() + + cls.test_model_part = cls.model.CreateModelPart("test") + cls.test_model_part.ProcessInfo.SetValue(Kratos.DOMAIN_SIZE, 3) + + for i in range(10): + cls.test_model_part.CreateNewNode(i + 1, i, i + 1,0.0) + + cls.position = Kratos.Expression.NodalExpression(cls.test_model_part) + Kratos.Expression.NodalPositionExpressionIO.Read(cls.position, Kratos.Configuration.Current) + + cls.optimization_problem = OptimizationProblem() + parameters = Kratos.Parameters("""{ + "type": "identity_projection" + }""") + cls.projection = CreateProjection(parameters, cls.optimization_problem) + cls.projection.SetProjectionSpaces([2.0, 3.0, 4.0], [200.0, 500.0, 1000.0]) + + def test_ProjectBackward(self): + result = self.projection.ProjectBackward(self.position) + self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result - self.position), 0.0) + + def test_ProjectForward(self): + result = self.projection.ProjectForward(self.position) + self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result - self.position), 0.0) + + def test_ForwardProjectionGradient(self): + result = self.projection.ForwardProjectionGradient(self.position) + self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result), numpy.sqrt(self.test_model_part.NumberOfNodes())) + + +class TestSigmoidalDesignVariableProjection(kratos_unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.model = Kratos.Model() + + cls.test_model_part = cls.model.CreateModelPart("test") + cls.test_model_part.ProcessInfo.SetValue(Kratos.DOMAIN_SIZE, 3) + + for i in range(10): + cls.test_model_part.CreateNewNode(i + 1, i * 4, i * 3, i * 2) + + cls.position = Kratos.Expression.NodalExpression(cls.test_model_part) + Kratos.Expression.NodalPositionExpressionIO.Read(cls.position, Kratos.Configuration.Current) + + cls.optimization_problem = OptimizationProblem() + parameters = Kratos.Parameters("""{ + "type" : "sigmoidal_projection", + "beta_value" : 2.0, + "penalty_factor": 1.2 + }""") + cls.projection = CreateProjection(parameters, cls.optimization_problem) + cls.projection.SetProjectionSpaces([2.0, 3.0, 4.0], [0.0, 500.0, 2000.0]) + + def test_ProjectBackward(self): + result = self.projection.ProjectBackward(self.position) + self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result - self.position), 83.57033231673704) + + def test_ProjectForward(self): + result = self.projection.ProjectForward(self.position) + self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result - self.position), 9874.416742272824) + + def test_ForwardProjectionGradient(self): + result = self.projection.ForwardProjectionGradient(self.position) + self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result), 1111.1477428336996) + +class TestAdaptiveSigmoidalDesignVariableProjection(kratos_unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.model = Kratos.Model() + + cls.test_model_part = cls.model.CreateModelPart("test") + cls.test_model_part.ProcessInfo.SetValue(Kratos.DOMAIN_SIZE, 3) + + for i in range(10): + cls.test_model_part.CreateNewNode(i + 1, i * 4, i * 3, i * 2) + + cls.position = Kratos.Expression.NodalExpression(cls.test_model_part) + Kratos.Expression.NodalPositionExpressionIO.Read(cls.position, Kratos.Configuration.Current) + + cls.parameters = Kratos.Parameters("""{ + "type" : "adaptive_sigmoidal_projection", + "initial_value" : 2.0, + "max_value" : 3.0, + "increase_fac" : 1.2, + "update_period" : 5, + "penalty_factor": 1.2 + }""") + + def test_ProjectBackward(self): + optimization_problem = OptimizationProblem() + projection = CreateProjection(self.parameters, optimization_problem) + projection.SetProjectionSpaces([2.0, 3.0, 4.0], [0.0, 500.0, 2000.0]) + + for i in range(5): + optimization_problem.AdvanceStep() + result = projection.ProjectBackward(self.position) + projection.Update() + self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result - self.position), 83.57033231673704) + + for i in range(5, 10): + optimization_problem.AdvanceStep() + result = projection.ProjectBackward(self.position) + projection.Update() + self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result - self.position), 82.98662649690897) + + for i in range(10, 15): + optimization_problem.AdvanceStep() + result = projection.ProjectBackward(self.position) + projection.Update() + self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result - self.position), 82.5032449721012) + + for i in range(15, 50): + optimization_problem.AdvanceStep() + result = projection.ProjectBackward(self.position) + projection.Update() + self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result - self.position), 82.40690497800159) + + def test_ProjectForward(self): + optimization_problem = OptimizationProblem() + projection = CreateProjection(self.parameters, optimization_problem) + projection.SetProjectionSpaces([2.0, 3.0, 4.0], [0.0, 500.0, 2000.0]) + + for i in range(5): + optimization_problem.AdvanceStep() + result = projection.ProjectForward(self.position) + projection.Update() + self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result - self.position), 9874.416742272824) + + for i in range(5, 10): + optimization_problem.AdvanceStep() + result = projection.ProjectForward(self.position) + projection.Update() + self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result - self.position), 9890.97484074556) + + for i in range(10, 15): + optimization_problem.AdvanceStep() + result = projection.ProjectForward(self.position) + projection.Update() + self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result - self.position), 9905.434754063906) + + for i in range(15, 50): + optimization_problem.AdvanceStep() + result = projection.ProjectForward(self.position) + projection.Update() + self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result - self.position), 9908.261739693658) + + def test_ForwardProjectionGradient(self): + optimization_problem = OptimizationProblem() + projection = CreateProjection(self.parameters, optimization_problem) + projection.SetProjectionSpaces([2.0, 3.0, 4.0], [0.0, 500.0, 2000.0]) + + for i in range(5): + optimization_problem.AdvanceStep() + result = projection.ForwardProjectionGradient(self.position) + projection.Update() + self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result - self.position), 1108.2457599723648) + + for i in range(5, 10): + optimization_problem.AdvanceStep() + result = projection.ForwardProjectionGradient(self.position) + projection.Update() + self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result - self.position), 966.0580001392216) + + for i in range(10, 15): + optimization_problem.AdvanceStep() + result = projection.ForwardProjectionGradient(self.position) + projection.Update() + self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result - self.position), 765.7187019597883) + + for i in range(15, 50): + optimization_problem.AdvanceStep() + result = projection.ForwardProjectionGradient(self.position) + projection.Update() + self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result - self.position), 716.3046437643214) + +if __name__ == "__main__": + kratos_unittest.main() \ No newline at end of file From bff24e578f61e84e99a7646d8f9ca75de81edccc Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Wed, 4 Feb 2026 07:40:30 +0100 Subject: [PATCH 034/116] add current changes --- .../add_custom_tensor_adaptors_to_python.cpp | 23 +- .../add_custom_utilities_to_python.cpp | 13 +- .../filtering/explicit_filter_utils.cpp | 5 - .../custom_utilities/optimization_utils.cpp | 119 ++++ .../custom_utilities/optimization_utils.h | 37 ++ .../python_scripts/controls/control.py | 45 +- .../python_scripts/controls/master_control.py | 136 +++-- .../material/material_properties_control.py | 37 +- .../filtering/explicit_filter.py | 33 +- .../python_scripts/filtering/filter.py | 25 +- .../python_scripts/filtering/filter_utils.py | 1 - .../responses/response_function.py | 12 +- .../responses/response_routine.py | 52 +- .../utilities/helper_utilities.py | 13 - .../utilities/opt_projection.py | 89 +-- .../utilities/union_utilities.py | 7 +- .../tests/control/test_master_control.py | 65 +- .../tests/filtering/explicit_filters_tests.py | 53 +- .../tests/test_component_data_view.py | 2 +- .../tests/test_design_variable_projection.py | 48 +- .../tests/test_optimization_utils.py | 132 ++++- .../tests/test_response_utilities.py | 16 +- .../python/add_tensor_adaptors_to_python.cpp | 554 +++++++++--------- .../geometry_metrics_tensor_adaptor.cpp | 151 +++++ .../geometry_metrics_tensor_adaptor.h | 119 ++++ kratos/tests/test_tensor_adaptors.py | 26 + 26 files changed, 1167 insertions(+), 646 deletions(-) create mode 100644 kratos/tensor_adaptors/geometry_metrics_tensor_adaptor.cpp create mode 100644 kratos/tensor_adaptors/geometry_metrics_tensor_adaptor.h diff --git a/applications/OptimizationApplication/custom_python/add_custom_tensor_adaptors_to_python.cpp b/applications/OptimizationApplication/custom_python/add_custom_tensor_adaptors_to_python.cpp index 6552a312cc9b..d200d1edb74e 100644 --- a/applications/OptimizationApplication/custom_python/add_custom_tensor_adaptors_to_python.cpp +++ b/applications/OptimizationApplication/custom_python/add_custom_tensor_adaptors_to_python.cpp @@ -34,11 +34,24 @@ void AddCustomTensorAdaptorsToPython(pybind11::module& m) auto tensor_adaptor_modules = m.def_submodule("TensorAdaptors"); py::class_(tensor_adaptor_modules, "PropertiesVariableTensorAdaptor") - .def(py::init(), py::arg("tensor_adaptor"), py::arg("variable"), py::arg("copy") = true) - .def(py::init(), py::arg("container"), py::arg("variable")) - .def(py::init&>(), py::arg("container"), py::arg("variable"), py::arg("data_shape")) - .def(py::init(), py::arg("container"), py::arg("variable")) - .def(py::init&>(), py::arg("container"), py::arg("variable"), py::arg("data_shape")) + .def(py::init(), + py::arg("tensor_adaptor"), + py::arg("variable"), + py::arg("copy") = true) + .def(py::init(), + py::arg("container"), + py::arg("variable")) + .def(py::init&>(), + py::arg("container"), + py::arg("variable"), + py::arg("data_shape")) + .def(py::init(), + py::arg("container"), + py::arg("variable")) + .def(py::init&>(), + py::arg("container"), + py::arg("variable"), + py::arg("data_shape")) ; } diff --git a/applications/OptimizationApplication/custom_python/add_custom_utilities_to_python.cpp b/applications/OptimizationApplication/custom_python/add_custom_utilities_to_python.cpp index a775dcb27651..56499a66898a 100644 --- a/applications/OptimizationApplication/custom_python/add_custom_utilities_to_python.cpp +++ b/applications/OptimizationApplication/custom_python/add_custom_utilities_to_python.cpp @@ -203,7 +203,18 @@ void AddCustomUtilitiesToPython(pybind11::module& m) .def("GetComponentWiseModelParts", &OptimizationUtils::GetComponentWiseModelParts, py::arg("model"), py::arg("parameters"), - py::return_value_policy::reference); + py::return_value_policy::reference) + .def("MapContainerDataToNodalData", OptimizationUtils::MapContainerDataToNodalData, + py::arg("input_tensor_adaptor"), + py::arg("nodes")) + .def("MapNodalDataToContainerData", OptimizationUtils::MapNodalDataToContainerData, + py::arg("input_tensor_adaptor"), + py::arg("conditions"), + py::arg("neighbour_count_tensor_adaptor")) + .def("MapNodalDataToContainerData", OptimizationUtils::MapNodalDataToContainerData, + py::arg("input_tensor_adaptor"), + py::arg("conditions"), + py::arg("neighbour_count_tensor_adaptor")) ; // Add collective expression to python diff --git a/applications/OptimizationApplication/custom_utilities/filtering/explicit_filter_utils.cpp b/applications/OptimizationApplication/custom_utilities/filtering/explicit_filter_utils.cpp index e09469a69ea5..e4d8b6713f9c 100644 --- a/applications/OptimizationApplication/custom_utilities/filtering/explicit_filter_utils.cpp +++ b/applications/OptimizationApplication/custom_utilities/filtering/explicit_filter_utils.cpp @@ -416,12 +416,7 @@ TensorAdaptor::Pointer ExplicitFilterUtils::GenericBackw const IndexType neighbour_id = rTLS.mNeighbourEntityPoints[neighbour_index]->Id(); const IndexType neighbour_data_begin_index = neighbour_id * stride; - // KRATOS_WATCH(neighbour_id) - // KRATOS_WATCH(weight) - AtomicAdd(result_data_view[neighbour_data_begin_index + j], origin_value * weight); - double temp = result_data_view[neighbour_data_begin_index + j]; - // std::cout << std::scientific << std::setprecision(18) << "temp:" << temp << std::endl; } } }); diff --git a/applications/OptimizationApplication/custom_utilities/optimization_utils.cpp b/applications/OptimizationApplication/custom_utilities/optimization_utils.cpp index 13a0d9188d83..2bee572e1fc5 100644 --- a/applications/OptimizationApplication/custom_utilities/optimization_utils.cpp +++ b/applications/OptimizationApplication/custom_utilities/optimization_utils.cpp @@ -18,6 +18,8 @@ #include "utilities/parallel_utilities.h" #include "utilities/reduction_utilities.h" #include "utilities/variable_utils.h" +#include "utilities/atomic_utilities.h" +#include "utilities/data_type_traits.h" // Application includes @@ -263,6 +265,120 @@ std::vector> OptimizationUtils::GetComponentWiseModelPar KRATOS_CATCH(""); } +TensorAdaptor::Pointer OptimizationUtils::MapContainerDataToNodalData( + const TensorAdaptor& rInput, + ModelPart::NodesContainerType::Pointer pNodes) +{ + KRATOS_TRY + + const auto& shape = rInput.Shape(); + const auto input_data = rInput.ViewData(); + + DenseVector output_shape(shape); + output_shape[0] = pNodes->size(); + + auto p_nd_data = Kratos::make_shared>(output_shape, 0.0); + auto p_result = Kratos::make_shared>(pNodes, p_nd_data, false); + auto output_data = p_nd_data->ViewData(); + + const auto number_of_components = std::accumulate(shape.begin() + 1, shape.end(), 1U, std::multiplies{}); + + std::visit([&rInput, &input_data, &pNodes, &output_data, number_of_components](const auto pContainer) { + using container_type = BareType; + + if constexpr(IsInList) { + IndexPartition(pContainer->size()).for_each([&pContainer,&pNodes, &rInput, &output_data, &input_data, number_of_components](const auto EntityIndex) { + const auto& r_geometry = (pContainer->begin() + EntityIndex)->GetGeometry(); + + for (const auto& r_node : r_geometry) { + auto p_node_itr = pNodes->find(r_node.Id()); + KRATOS_ERROR_IF(p_node_itr == pNodes->end()) + << "The node with id = " << r_node.Id() + << " in entity with id = " << (pContainer->begin() + EntityIndex)->Id() + << " not found in the provided neighbour entities container [ " + << " input tensor adaptor = " << rInput << " ].\n"; + + const auto node_index = std::distance(pNodes->begin(), pNodes->find(r_node.Id())); + + for (IndexType i_comp = 0; i_comp < number_of_components; ++i_comp) { + AtomicAdd( + output_data[node_index * number_of_components + i_comp], + input_data[EntityIndex * number_of_components + i_comp] / r_geometry.size()); + } + } + }); + + } else { + KRATOS_ERROR << "The input tensor adaptor should have data based on conditions / elements [ input tensor adaptor = " << rInput << " ].\n"; + } + }, rInput.GetContainer()); + + return p_result; + + KRATOS_CATCH(""); +} + +template +TensorAdaptor::Pointer OptimizationUtils::MapNodalDataToContainerData( + const TensorAdaptor& rInput, + TContainerPointerType pEntities, + const TensorAdaptor& rNeighbourCount) +{ + KRATOS_TRY + + const auto& shape = rInput.Shape(); + const auto input_data = rInput.ViewData(); + const auto neighbour_data = rNeighbourCount.ViewData(); + + DenseVector output_shape(shape); + output_shape[0] = pEntities->size(); + + auto p_nd_data = Kratos::make_shared>(output_shape, 0.0); + auto p_result = Kratos::make_shared>(pEntities, p_nd_data, false); + auto output_data = p_nd_data->ViewData(); + + const auto number_of_components = std::accumulate(shape.begin() + 1, shape.end(), 1U, std::multiplies{}); + + if (!std::holds_alternative(rInput.GetContainer()) || + !std::holds_alternative(rNeighbourCount.GetContainer())) { + KRATOS_ERROR + << "Input container and neighbour container count tensor adaptors should be having nodal containers [ input tensor adaptor = " + << rInput << ", neighbour count tensor adaptor = " << rNeighbourCount << " ].\n"; + } + + const auto& r_nodes = *std::get(rInput.GetContainer()); + + if (&r_nodes != &*(std::get(rNeighbourCount.GetContainer()))) { + KRATOS_ERROR + << "The nodal containers in input and neighbour count tensor adaptors mismatch [ " + << "input tensor adaptor = " << rInput << ", neighbour count tensor adaptor = " << rNeighbourCount << " ].\n"; + } + + IndexPartition(pEntities->size()).for_each([&input_data, &output_data, &neighbour_data, &r_nodes, &pEntities, &rInput, &rNeighbourCount, number_of_components](const auto EntityIndex) { + const auto& r_geometry = (pEntities->begin() + EntityIndex)->GetGeometry(); + + for (const auto& r_node : r_geometry) { + auto p_node_itr = r_nodes.find(r_node.Id()); + + KRATOS_ERROR_IF(p_node_itr == r_nodes.end()) + << "The node with id = " << r_node.Id() << " in entity with id = " + << (pEntities->begin() + EntityIndex)->Id() << " is not found in the nodes of the input tensor adaptor [ " + << "input tensor adaptor = " << rInput << ", neighbour count tensor adaptor = " << rNeighbourCount << " ].\n"; + + const IndexType node_index = std::distance(r_nodes.begin(), p_node_itr); + + for (IndexType i_comp = 0; i_comp < number_of_components; ++i_comp) { + AtomicAdd(output_data[EntityIndex * number_of_components + i_comp], + input_data[node_index * number_of_components + i_comp] / neighbour_data[node_index]); + } + } + }); + + return p_result; + + KRATOS_CATCH(""); +} + // template instantiations #ifndef KRATOS_OPTIMIZATION_UTILS_UPDATE_PROPERTIES_VARIABLE_RECURSIVELY #define KRATOS_OPTIMIZATION_UTILS_UPDATE_PROPERTIES_VARIABLE_RECURSIVELY(CONTAINER_TYPE) \ @@ -299,4 +415,7 @@ template KRATOS_API(OPTIMIZATION_APPLICATION) bool OptimizationUtils::IsVariable template KRATOS_API(OPTIMIZATION_APPLICATION) bool OptimizationUtils::IsVariableExistsInAtLeastOneContainerProperties(const ModelPart::ConditionsContainerType&, const Variable>&, const DataCommunicator& rDataCommunicator); template KRATOS_API(OPTIMIZATION_APPLICATION) bool OptimizationUtils::IsVariableExistsInAtLeastOneContainerProperties(const ModelPart::ElementsContainerType&, const Variable>&, const DataCommunicator& rDataCommunicator); +template KRATOS_API(OPTIMIZATION_APPLICATION) TensorAdaptor::Pointer OptimizationUtils::MapNodalDataToContainerData(const TensorAdaptor&, ModelPart::ConditionsContainerType::Pointer, const TensorAdaptor&); +template KRATOS_API(OPTIMIZATION_APPLICATION) TensorAdaptor::Pointer OptimizationUtils::MapNodalDataToContainerData(const TensorAdaptor&, ModelPart::ElementsContainerType::Pointer, const TensorAdaptor&); + } \ No newline at end of file diff --git a/applications/OptimizationApplication/custom_utilities/optimization_utils.h b/applications/OptimizationApplication/custom_utilities/optimization_utils.h index af2831a3deb7..d1110425f32b 100644 --- a/applications/OptimizationApplication/custom_utilities/optimization_utils.h +++ b/applications/OptimizationApplication/custom_utilities/optimization_utils.h @@ -22,6 +22,7 @@ #include "includes/data_communicator.h" #include "includes/kratos_parameters.h" #include "containers/model.h" +#include "tensor_adaptors/tensor_adaptor.h" // Application includes @@ -111,6 +112,42 @@ class KRATOS_API(OPTIMIZATION_APPLICATION) OptimizationUtils Model& rModel, Parameters Settings); + /** + * @brief Maps container data to nodal data + * + * This method returns a mapped container data given in @p rInput to nodal given by @p pNodes. + * + * @throws std::runtime_error if the container in @p rInput is not of type conditions or elements. + * @throws std::runtime_error if the entities in @p rInput 's container contain nodes which are not found in the @p pNodes. + * + * @param rInput Input containing values in which needs to be mapped to nodes (container should be conditions or elements). + * @param pNodes List of nodes to which the values will be mapped out. + * @returns Returns a tensor adaptor having the container @p pNodes with the mapped values. + */ + static TensorAdaptor::Pointer MapContainerDataToNodalData( + const TensorAdaptor& rInput, + ModelPart::NodesContainerType::Pointer pNodes); + + /** + * @brief Maps nodal data to a specific container data + * + * This method returns a mapped nodal data given in @p rInput to container given by @p pEntities. + * + * @throws std::runtime_error if the container in @p rInput is not a nodal container. + * @throws std::runtime_error if the nodal container in @p rInput is not same as nodal container in @p rNeighbourCount . + * @throws std::runtime_error if the entities in @p rInput 's container contain nodes which are not found in the nodal container of @p rInput . + * + * @param rInput Input containing values in which needs to be mapped to conditions / elements (container should be nodal). + * @param pEntities List of entities to which the values will be mapped out. + * @param rNeighbourCount Number of neighbour entities around each node. + * @returns Returns a tensor adaptor having the container @p pEntities with the mapped values. + */ + template + static TensorAdaptor::Pointer MapNodalDataToContainerData( + const TensorAdaptor& rInput, + TContainerPointerType pEntities, + const TensorAdaptor& rNeighbourCount); + ///@} }; diff --git a/applications/OptimizationApplication/python_scripts/controls/control.py b/applications/OptimizationApplication/python_scripts/controls/control.py index 90e157b69809..c76feca4215e 100644 --- a/applications/OptimizationApplication/python_scripts/controls/control.py +++ b/applications/OptimizationApplication/python_scripts/controls/control.py @@ -1,6 +1,6 @@ from abc import ABC, abstractmethod +import KratosMultiphysics as Kratos from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes -from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import ContainerExpressionTypes class Control(ABC): """Base abstract control class. @@ -64,67 +64,56 @@ def GetPhysicalKratosVariables(self) -> 'list[SupportedSensitivityFieldVariableT pass @abstractmethod - def GetEmptyField(self) -> ContainerExpressionTypes: + def GetEmptyField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: """Returns a new empty data field holder with correct dimensionality information. This returns a new empty data field holder to give information about on which model part's container - this model part is acting on. This has O(1) complexity, hence has the least cost because it does not read - any data from respective model part's container. - - Dimensionality information is provided by calling a ContainerExpression::SetData(value). This creates a single - memory allocation for whole container with the dimensions of the variable. This operation is cheap in memory and - consumes least time. - - Eg: - 1. If the control field is a scalar, then container_expression.SetData(0.0) - 2. If the control field is a array3, then container_expression.SetData(Kratos.Array3(0.0)) + this model part is acting on. It does not read any data from respective model part's container. Returns: - ContainerExpressionTypes: Returns a new empty ContainerExpression corresponding to control's model part's respective container. + Kratos.TensorAdaptors.DoubleTensorAdaptor: Returns a new empty @ref Kratos.TensorAdaptor corresponding to control's model part's respective container. """ pass @abstractmethod - def GetControlField(self) -> ContainerExpressionTypes: + def GetControlField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: """Returns the current control field of the control. This method returns the control field of the current design. Returns: - ContainerExpressionTypes: Current designs control field. + Kratos.TensorAdaptors.DoubleTensorAdaptor: Current designs control field. """ pass @abstractmethod - def MapGradient(self, physical_gradient_variable_container_expression_map: 'dict[SupportedSensitivityFieldVariableTypes, ContainerExpressionTypes]') -> ContainerExpressionTypes: + def MapGradient(self, physical_gradient_variable_tensor_adaptor_map: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleTensorAdaptor]') -> Kratos.TensorAdaptors.DoubleTensorAdaptor: """Maps physical space gradients to the control space. This method is used to map the given physical space gradients to the control space. The input should be as in the following example: - physical_gradient_variable_container_expression_map = { - Kratos.YOUNG_MODULUS: Kratos.ContainerExpressions.NodalNonHistoricalContainer, - Kratos.DENSITY : Kratos.ContainerExpressions.ElementNonHistoricalContainer, - Kratos.SHAPE : Kratos.ContainerExpressions.ElementNonHistoricalContainer + physical_gradient_variable_tensor_adaptor_map = { + Kratos.YOUNG_MODULUS: Kratos.DoubleTensorAdaptor, + Kratos.DENSITY : Kratos.DoubleTensorAdaptor, + Kratos.SHAPE : Kratos.DoubleTensorAdaptor } - All the gradients w.r.t. @see GetPhysicalKratosVariables() variables will be given in @ref physical_gradient_variable_container_expression_map. - If the response does not depend on some of them or all, then container expressions with ContainerExpression::SetDataToZero() performed will be passed. - [ContainerExpression::SetDataToZero() will make the container expression to zero, but will only allocate one double value for the - whole container, hence it is cheap in memory and execution.] + All the gradients w.r.t. @see GetPhysicalKratosVariables() variables will be given in @ref physical_gradient_variable_tensor_adaptor_map. + If the response does not depend on some of them or all, then @ref Kratos.TensorAdaptor with correctly sized zero tensors will be passed. Args: - physical_gradient_variable_container_expression_map (dict[SupportedSensitivityFieldVariableTypes, ContainerExpressionTypes]): Map of physical space variable and ContainerExpression with sensitivities. + physical_gradient_variable_tensor_adaptor_map (dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleTensorAdaptor]): Map of physical space variable and @ref Kratos::TensorAdaptor with sensitivities. Returns: - ContainerExpressionTypes: Gradients mapped in to control space. + Kratos.TensorAdaptors.DoubleTensorAdaptor: Gradients mapped in to control space. """ pass @abstractmethod - def Update(self, control_field: ContainerExpressionTypes) -> bool: + def Update(self, control_field: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> bool: """Modifies the current control with the given control field. Args: - control_field (ContainerExpressionTypes): The control field in control space. + control_field (Kratos.TensorAdaptors.DoubleTensorAdaptor): The control field in control space. Returns: bool: True if the control field was applied to obtain a new design, otherwise False diff --git a/applications/OptimizationApplication/python_scripts/controls/master_control.py b/applications/OptimizationApplication/python_scripts/controls/master_control.py index 30e100618ca3..0b67b893f7d6 100644 --- a/applications/OptimizationApplication/python_scripts/controls/master_control.py +++ b/applications/OptimizationApplication/python_scripts/controls/master_control.py @@ -1,9 +1,7 @@ +import typing import KratosMultiphysics as Kratos -import KratosMultiphysics.OptimizationApplication as KratosOA from KratosMultiphysics.OptimizationApplication.controls.control import Control from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes -from KratosMultiphysics.OptimizationApplication.utilities.helper_utilities import IsSameContainerExpression -from KratosMultiphysics.OptimizationApplication.utilities.helper_utilities import HasContainerExpression from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import time_decorator from KratosMultiphysics.OptimizationApplication.utilities.helper_utilities import CallOnAll @@ -11,8 +9,8 @@ class MasterControl: """Master control class. This class is used to simplify working with many controls at once. Following responsibilities are assumed: - 1. Maps physical gradients from different domains to one CollectiveExpression (using MapGradient). - 2. Updates each respective domain from updates given by one CollectiveExpression (using Update). + 1. Maps physical gradients from different domains to one @ref Kratos::CombinedTensorAdaptor (using MapGradient). + 2. Updates each respective domain from updates given by one @ref Kratos::CombinedTensorAdaptor (using Update). There should be only one master control class per optimization problem. @@ -36,69 +34,65 @@ def GetListOfControls(self) -> 'list[Control]': """ return self.__list_of_controls - def GetPhysicalKratosVariableCollectiveExpressionsMap(self) -> 'dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]': - """Returns map of physical variables and collective expressions from each control. + def GetPhysicalKratosVariableCombinedTensorAdaptorsMap(self) -> 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]': + """Returns map of physical variables and @ref Kratos::CombinedTensorAdaptor from each control. - This returns a map of physical control variables and a collective expressions. The collective expressions will contain - all the container expressions for respective control's control domains for each physical control variable. The repeated container - expressions for the same physical control variable is omitted to avoid double calculations. + This returns a map of physical control variables and a @ref Kratos::CombinedTensorAdaptor. The @ref Kratos::CombinedTensorAdaptor will contain + all the @ref Kratos::TensorAdaptor for respective control's control domains for each physical control variable. The repeated @ref Kratos::TensorAdaptor s + for the same physical control variable is omitted to avoid double calculations. Returns: - dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]: Physical control variable and collective expressions map. + dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]: Physical control variable and @ref Kratos::CombinedTensorAdaptor map. """ - physical_variable_collective_expressions: 'dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]' = {} + physical_variable_containers_dict: 'dict[SupportedSensitivityFieldVariableTypes, list[typing.Union[Kratos.NodesArray, Kratos.ElementsArray, Kratos.ConditionsArray]]]' = {} for control in self.__list_of_controls: for physical_variable in control.GetPhysicalKratosVariables(): # check whether the physical variable is already there. - if not physical_variable in physical_variable_collective_expressions.keys(): - physical_variable_collective_expressions[physical_variable] = KratosOA.CollectiveExpression() - - current_variable_collective_expression = physical_variable_collective_expressions[physical_variable] + if not physical_variable in physical_variable_containers_dict.keys(): + physical_variable_containers_dict[physical_variable] = [] # check whether the container for that physical variable is already there. - control_container_expression = control.GetEmptyField() - if not HasContainerExpression(control_container_expression, current_variable_collective_expression.GetContainerExpressions()): - current_variable_collective_expression.Add(control_container_expression) + control_ta = control.GetEmptyField() + if control_ta.GetContainer() not in physical_variable_containers_dict[physical_variable]: + physical_variable_containers_dict[physical_variable].append(control_ta.GetContainer()) + + physical_variable_combined_ta_dict: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]' = {} + for variable, containers_list in physical_variable_containers_dict.items(): + physical_variable_combined_ta_dict[variable] = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.DoubleTensorAdaptor(Kratos.TensorAdaptors.VariableTensorAdaptor(container, variable), copy=False) for container in containers_list], perform_collect_data_recursively=False, perform_store_data_recursively=False) - return physical_variable_collective_expressions + return physical_variable_combined_ta_dict - def GetEmptyField(self) -> KratosOA.CollectiveExpression: + def GetEmptyField(self) -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: """Returns empty CollectiveExpression containing empty ContainerExpressions for each control. Returns: - KratosOA.CollectiveExpression: Empty CollectiveExpression + Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: Empty CollectiveExpression """ - empty_control_fields = KratosOA.CollectiveExpression() - - for control in self.__list_of_controls: - empty_control_fields.Add(control.GetEmptyField()) + ta = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([control.GetEmptyField() for control in self.__list_of_controls], perform_collect_data_recursively=False, perform_store_data_recursively=False) + ta.CollectData() # reading all the data from each ta adaptor to the combined tensor adaptor + return ta - return empty_control_fields - - def GetControlField(self) -> KratosOA.CollectiveExpression: + def GetControlField(self) -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: """Returns CollectiveExpression containing control field ContainerExpressions for each control. Returns: - KratosOA.CollectiveExpression: Control field CollectiveExpression + Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: Control field CollectiveExpression """ - control_fields = KratosOA.CollectiveExpression() - - for control in self.__list_of_controls: - control_fields.Add(control.GetControlField()) - - return control_fields + ta = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([control.GetControlField() for control in self.__list_of_controls], perform_collect_data_recursively=False, perform_store_data_recursively=False) + ta.CollectData() # reading all the data from each ta adaptor to the combined tensor adaptor + return ta @time_decorator() - def MapGradient(self, physical_space_gradient_variable_and_collective_expressions_map: 'dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]') -> KratosOA.CollectiveExpression: - """Maps physical space gradients to a collective expression. + def MapGradient(self, physical_space_gradient_variable_and_combined_tensor_adaptor_map: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]') -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: + """Maps physical space gradients to a combined tensor adaptor. This method maps sensitivities w.r.t. physical space variables to control space by using each control. It is done by converting input - map with CollectiveExpression to a map with ContainerExpressions. The following is a pseudo example: + map with @ref Kratos::CombinedTensorAdaptor to a map with @ref Kratos::TensorAdaptor. The following is a pseudo example: input: - physical_space_gradient_variable_and_collective_expressions_map = { + physical_space_gradient_variable_and_combined_tensor_adaptor_map = { "YOUND_MODULUS": [ControlDomain1, ControlDomain2], "DENSITY" : [ControlDomain1], "VISCOSITY" : [ControlDomain2], @@ -112,76 +106,78 @@ def MapGradient(self, physical_space_gradient_variable_and_collective_expression physical_vars = VISCOSITY, DENSITY - from above information, following two maps are created and passed to each control to obtain one ContainerExpression from each control. + from above information, following two maps are created and passed to each control to obtain one @ref Kratos::TensorAdaptor from each control. control_specific_maps: for control1: {YOUND_MODULUS: ControlDomain1, DENSITY: ControlDomain1} for control2: {VISCOSITY: ControlDomain2, DENSITY: A zero valued ControlDomain} - then returned mapped gradients are added to one CollectiveExpression. + then returned mapped gradients are added to one @ref Kratos::CombinedTensorAdaptor. In here, the missing gradients for required physical variables will be assumed to be zero. This converts given map of sensitivities w.r.t. different physical space variables to one sensitivities in control space and aggregated - to one CollectiveExpression. + to one @ref Kratos::CombinedTensorAdaptor. Args: - physical_space_gradient_variable_and_collective_expressions_map (dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]): Map of physical space sensitivities. + physical_space_gradient_variable_and_combined_tensor_adaptor_map (dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]): Map of physical space sensitivities. Returns: - KratosOA.CollectiveExpression: Control space sensitivities. + Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: Control space sensitivities. """ - mapped_gradients = KratosOA.CollectiveExpression() + mapped_gradients: 'list[Kratos.TensorAdaptors.DoubleTensorAdaptor]' = [] for control in self.__list_of_controls: - # iterate through each control to create its own container expression map from the collective expressions map given as input - control_physical_sensitivities_container_expression_map = {} + # iterate through each control to create its own container map from the combined tensor adaptor map given as input + control_physical_sensitivities_container_expression_map: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleTensorAdaptor]' = {} for physical_control_variable in control.GetPhysicalKratosVariables(): - # first assume the gradients for this physical_control_variable is zero, hence get the zero valued expression. - control_expression = control.GetEmptyField() + # first assume the gradients for this physical_control_variable is zero, hence get the zero valued tensor adaptor. + control_ta = control.GetEmptyField() # get the required physical variables from control. - if physical_control_variable in physical_space_gradient_variable_and_collective_expressions_map.keys(): + if physical_control_variable in physical_space_gradient_variable_and_combined_tensor_adaptor_map.keys(): # if the sensitivities for the given physical control variable exists, then try to find whether # for this specific control the physical control variable sensitivities exists. - sensitivity_collective_expression = physical_space_gradient_variable_and_collective_expressions_map[physical_control_variable] - for container_expression in sensitivity_collective_expression.GetContainerExpressions(): - if IsSameContainerExpression(control_expression, container_expression): - # there exists for this control's physical variables sensitivities. then copy it to the expression - # this copy moves the underlying vectors, hence cheap. - control_expression.CopyFrom(container_expression) + sensitivity_cta = physical_space_gradient_variable_and_combined_tensor_adaptor_map[physical_control_variable] + for ta in sensitivity_cta.GetTensorAdaptors(): + if ta.GetContainer() == control_ta.GetContainer(): + # there exists for this control's physical variables sensitivities. + control_physical_sensitivities_container_expression_map[physical_control_variable] = ta break - # now add it to the map. If it is found from input gradients, the control_expression will have those values, - # otherwise it will have representative zero control_expression. - control_physical_sensitivities_container_expression_map[physical_control_variable] = control_expression + if physical_control_variable not in control_physical_sensitivities_container_expression_map.keys(): + # If it is found from input gradients, the control_expression will have those values, + # otherwise it will have representative zero control_expression. + control_physical_sensitivities_container_expression_map[physical_control_variable] = control_ta # map the physical control variable sensitivities to one control space - mapped_gradients.Add(control.MapGradient(control_physical_sensitivities_container_expression_map)) + mapped_gradients.append(control.MapGradient(control_physical_sensitivities_container_expression_map)) - return mapped_gradients + result = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([mapped_gradient for mapped_gradient in mapped_gradients], perform_collect_data_recursively=False, perform_store_data_recursively=False) + result.CollectData() + return result @time_decorator() - def Update(self, update_collective_expressions: KratosOA.CollectiveExpression) -> 'dict[Control, bool]': - """Update each control with given collective expression's respective container expression. + def Update(self, update_combined_tensor_adaptor: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor) -> 'dict[Control, bool]': + """Update each control with given combined tensor adaptor's respective tensor adaptor. Args: - update_collective_expressions (KratosOA.CollectiveExpression): Update + update_combined_tensor_adaptor (Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor): Update Raises: - RuntimeError: If number of controls and number of container expressions mismatch. + RuntimeError: If number of controls and number of tensor adaptors mismatch. Returns: dict[Control, bool]: A map with control and a boolean whether the update changed anything in that control. """ - if len(self.__list_of_controls) != len(update_collective_expressions.GetContainerExpressions()): - raise RuntimeError(f"Controls size and update size mismatch [ number of controls: {len(self.__list_of_controls)}, number of container expressions: {len(update_collective_expressions.GetContainerExpressions())} ].") + if len(self.__list_of_controls) != len(update_combined_tensor_adaptor.GetTensorAdaptors()): + raise RuntimeError(f"Controls size and update size mismatch [ number of controls: {len(self.__list_of_controls)}, number of tensor adaptors: {len(update_combined_tensor_adaptor.GetTensorAdaptors())} ].") update_map: 'dict[Control, bool]' = {} - for control, container_expression in zip(self.__list_of_controls, update_collective_expressions.GetContainerExpressions()): - update_map[control] = control.Update(container_expression) + for control, ta in zip(self.__list_of_controls, update_combined_tensor_adaptor.GetTensorAdaptors()): + update_map[control] = control.Update(ta) if update_map[control]: Kratos.Logger.PrintInfo(f"Control {control.GetName()} updated.") else: diff --git a/applications/OptimizationApplication/python_scripts/controls/material/material_properties_control.py b/applications/OptimizationApplication/python_scripts/controls/material/material_properties_control.py index 9603512ee186..918c67f472be 100644 --- a/applications/OptimizationApplication/python_scripts/controls/material/material_properties_control.py +++ b/applications/OptimizationApplication/python_scripts/controls/material/material_properties_control.py @@ -1,11 +1,10 @@ +import numpy from typing import Optional import KratosMultiphysics as Kratos import KratosMultiphysics.OptimizationApplication as KratosOA from KratosMultiphysics.OptimizationApplication.controls.control import Control -from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import ContainerExpressionTypes from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes -from KratosMultiphysics.OptimizationApplication.utilities.helper_utilities import IsSameContainerExpression from KratosMultiphysics.OptimizationApplication.utilities.model_part_utilities import ModelPartOperation def Factory(model: Kratos.Model, parameters: Kratos.Parameters, _) -> Control: @@ -68,17 +67,17 @@ def Finalize(self) -> None: def GetPhysicalKratosVariables(self) -> 'list[SupportedSensitivityFieldVariableTypes]': return [self.controlled_physical_variable] - def GetEmptyField(self) -> ContainerExpressionTypes: - field = Kratos.Expression.ElementExpression(self.model_part) - Kratos.Expression.LiteralExpressionIO.SetData(field, 0.0) - return field + def GetEmptyField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + field = KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(self.model_part.Elements, self.controlled_physical_variable) + field.data[:] = 0.0 + return Kratos.TensorAdaptors.DoubleTensorAdaptor(field, copy=False) - def GetControlField(self) -> ContainerExpressionTypes: - field = self.GetEmptyField() - KratosOA.PropertiesVariableExpressionIO.Read(field, self.controlled_physical_variable) - return field + def GetControlField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + field = KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(self.model_part.Elements, self.controlled_physical_variable) + field.CollectData() + return Kratos.TensorAdaptors.DoubleTensorAdaptor(field, copy=False) - def MapGradient(self, physical_gradient_variable_container_expression_map: 'dict[SupportedSensitivityFieldVariableTypes, ContainerExpressionTypes]') -> ContainerExpressionTypes: + def MapGradient(self, physical_gradient_variable_container_expression_map: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleTensorAdaptor]') -> Kratos.TensorAdaptors.DoubleTensorAdaptor: keys = physical_gradient_variable_container_expression_map.keys() if len(keys) != 1: raise RuntimeError(f"Provided more than required gradient fields for control \"{self.GetName()}\". Following are the variables:\n\t" + "\n\t".join([k.Name() for k in keys])) @@ -86,15 +85,15 @@ def MapGradient(self, physical_gradient_variable_container_expression_map: 'dict raise RuntimeError(f"The required gradient for control \"{self.GetName()}\" w.r.t. {self.controlled_physical_variable.Name()} not found. Followings are the variables:\n\t" + "\n\t".join([k.Name() for k in keys])) physical_gradient = physical_gradient_variable_container_expression_map[self.controlled_physical_variable] - if not IsSameContainerExpression(physical_gradient, self.GetEmptyField()): - raise RuntimeError(f"Gradients for the required element container not found for control \"{self.GetName()}\". [ required model part name: {self.model_part.FullName()}, given model part name: {physical_gradient.GetModelPart().FullName()} ]") + if physical_gradient.GetContainer() != self.GetEmptyField().GetContainer(): + raise RuntimeError(f"Gradients for the required element container not found for control \"{self.GetName()}\". [ required model part name: {self.model_part.FullName()} ]") # TODO: Implement filtering mechanisms here - return physical_gradient_variable_container_expression_map[self.controlled_physical_variable].Clone() + return Kratos.TensorAdaptors.DoubleTensorAdaptor(physical_gradient_variable_container_expression_map[self.controlled_physical_variable]) - def Update(self, control_field: ContainerExpressionTypes) -> bool: - if not IsSameContainerExpression(control_field, self.GetEmptyField()): - raise RuntimeError(f"Updates for the required element container not found for control \"{self.GetName()}\". [ required model part name: {self.model_part.FullName()}, given model part name: {control_field.GetModelPart().FullName()} ]") + def Update(self, control_field: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> bool: + if control_field.GetContainer() != self.GetEmptyField().GetContainer(): + raise RuntimeError(f"Updates for the required element container not found for control \"{self.GetName()}\". [ required model part name: {self.model_part.FullName()} ]") # TODO: Implement inverse filtering mechanisms here # since no filtering is implemented yet, we are checking the unfiltered updates with the filtered updates. This needs to be changed once the @@ -103,8 +102,8 @@ def Update(self, control_field: ContainerExpressionTypes) -> bool: # get the current unfiltered control field unfiltered_control_field = self.GetControlField() - if Kratos.Expression.Utils.NormL2(unfiltered_control_field - control_field) > 1e-9: - KratosOA.PropertiesVariableExpressionIO.Write(control_field, self.controlled_physical_variable) + if numpy.linalg.norm(unfiltered_control_field.data - control_field.data) > 1e-9: + KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(control_field, self.controlled_physical_variable, copy=False).StoreData() if self.consider_recursive_property_update: KratosOA.OptimizationUtils.UpdatePropertiesVariableWithRootValueRecursively(control_field.GetContainer(), self.controlled_physical_variable) diff --git a/applications/OptimizationApplication/python_scripts/filtering/explicit_filter.py b/applications/OptimizationApplication/python_scripts/filtering/explicit_filter.py index 876b2636ccda..3267c82dc74a 100644 --- a/applications/OptimizationApplication/python_scripts/filtering/explicit_filter.py +++ b/applications/OptimizationApplication/python_scripts/filtering/explicit_filter.py @@ -6,7 +6,6 @@ from KratosMultiphysics.OptimizationApplication.filtering.filter import Filter from KratosMultiphysics.OptimizationApplication.filtering.filter_utils import FilterRadiusFactory from KratosMultiphysics.OptimizationApplication.filtering.filter_utils import ExplicitFilterDampingFactory -from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import ContainerExpressionTypes from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes def Factory(model: Kratos.Model, filtering_model_part_name: str, filtering_variable: SupportedSensitivityFieldVariableTypes, data_location: Kratos.Globals.DataLocation, parameters: Kratos.Parameters) -> Filter: @@ -104,30 +103,20 @@ def Check(self) -> None: def Finalize(self) -> None: pass - def ForwardFilterField(self, control_field: ContainerExpressionTypes) -> ContainerExpressionTypes: - temp_ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(control_field.GetContainer(), Kratos.DoubleNDData(control_field.Evaluate()), False) - result_ta = self.filter_utils.ForwardFilterField(temp_ta) - result = control_field.Clone() - Kratos.Expression.CArrayExpressionIO.Read(result, result_ta.data) - return result + def ForwardFilterField(self, control_field: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + return self.filter_utils.ForwardFilterField(control_field) - def BackwardFilterField(self, physical_mesh_independent_gradient_field: ContainerExpressionTypes) -> ContainerExpressionTypes: - temp_ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(physical_mesh_independent_gradient_field.GetContainer(), Kratos.DoubleNDData(physical_mesh_independent_gradient_field.Evaluate()), False) - result_ta = self.filter_utils.BackwardFilterField(temp_ta) - result = physical_mesh_independent_gradient_field.Clone() - Kratos.Expression.CArrayExpressionIO.Read(result, result_ta.data) - return result + def BackwardFilterField(self, physical_mesh_independent_gradient_field: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + return self.filter_utils.BackwardFilterField(physical_mesh_independent_gradient_field) - def BackwardFilterIntegratedField(self, physical_mesh_dependent_gradient_field: ContainerExpressionTypes) -> ContainerExpressionTypes: - temp_ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(physical_mesh_dependent_gradient_field.GetContainer(), Kratos.DoubleNDData(physical_mesh_dependent_gradient_field.Evaluate()), False) - result_ta = self.filter_utils.BackwardFilterIntegratedField(temp_ta) - result = physical_mesh_dependent_gradient_field.Clone() - Kratos.Expression.CArrayExpressionIO.Read(result, result_ta.data) - return result + def BackwardFilterIntegratedField(self, physical_mesh_dependent_gradient_field: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + return self.filter_utils.BackwardFilterIntegratedField(physical_mesh_dependent_gradient_field) - def UnfilterField(self, filtered_field: ContainerExpressionTypes) -> ContainerExpressionTypes: - # WARNING: In general explicit VM doesn't need unfiltered field because it works with changes. Hence, it returns zeros and optimization runs correctly. - return Kratos.Expression.Utils.Collapse(filtered_field * 0.0) + def UnfilterField(self, filtered_field: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + # WARNING: In general explicit VM doesn't need unfiltered field because it works with changes. Hence, it returns zeros and optimization runs correctly. + result = Kratos.TensorAdaptors.DoubleTensorAdaptor(filtered_field) + result.data[:] = 0.0 + return result def GetBoundaryConditions(self) -> 'list[list[Kratos.ModelPart]]': return self.damping.GetDampedModelParts() diff --git a/applications/OptimizationApplication/python_scripts/filtering/filter.py b/applications/OptimizationApplication/python_scripts/filtering/filter.py index 4d0d49c742e6..071bd72efac0 100644 --- a/applications/OptimizationApplication/python_scripts/filtering/filter.py +++ b/applications/OptimizationApplication/python_scripts/filtering/filter.py @@ -3,7 +3,6 @@ from importlib import import_module import KratosMultiphysics as Kratos -from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import ContainerExpressionTypes from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView @@ -74,62 +73,62 @@ def Finalize(self) -> None: pass @abc.abstractmethod - def ForwardFilterField(self, control_field: ContainerExpressionTypes) -> ContainerExpressionTypes: + def ForwardFilterField(self, control_field: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: """Return the physical field by filtering/smoothing control field This method filters the passed input field. control_field field is assumed to be a mesh-independent field. Args: - control_field (ContainerExpressionTypes): Input control field + control_field (Kratos.TensorAdaptors.DoubleTensorAdaptor): Input control field Returns: - ContainerExpressionTypes: Physical field. + Kratos.TensorAdaptors.DoubleTensorAdaptor: Physical field. """ pass @abc.abstractmethod - def BackwardFilterField(self, physical_mesh_independent_gradient_field: ContainerExpressionTypes) -> ContainerExpressionTypes: + def BackwardFilterField(self, physical_mesh_independent_gradient_field: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: """Returns mesh-independent control space gradient from mesh-independent physical space gradient. This method filters the passed mesh-independent input field. This is not the inverse operator, it uses the transpose of the ForwardFilterField matrix. Args: - physical_mesh_independent_gradient_field (ContainerExpressionTypes): Mesh independent gradient field in physical space. + physical_mesh_independent_gradient_field (Kratos.TensorAdaptors.DoubleTensorAdaptor): Mesh independent gradient field in physical space. Returns: - ContainerExpressionTypes: Mesh-independent gradient in the control space. + Kratos.TensorAdaptors.DoubleTensorAdaptor: Mesh-independent gradient in the control space. """ pass @abc.abstractmethod - def BackwardFilterIntegratedField(self, physical_mesh_dependent_gradient_field: ContainerExpressionTypes) -> ContainerExpressionTypes: + def BackwardFilterIntegratedField(self, physical_mesh_dependent_gradient_field: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: """Returns mesh-independent control space gradient from mesh-dependent physical space gradient. This method filters the passed mesh-dependent input field. This is not the inverse operator, it uses the transpose of the ForwardFilterField matrix. Args: - physical_mesh_dependent_gradient_field (ContainerExpressionTypes): Mesh dependent gradient field in physical space. + physical_mesh_dependent_gradient_field (Kratos.TensorAdaptors.DoubleTensorAdaptor): Mesh dependent gradient field in physical space. Returns: - ContainerExpressionTypes: Mesh-independent gradient in the control space. + Kratos.TensorAdaptors.DoubleTensorAdaptor: Mesh-independent gradient in the control space. """ pass @abc.abstractmethod - def UnfilterField(self, physical_field: ContainerExpressionTypes) -> ContainerExpressionTypes: + def UnfilterField(self, physical_field: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: """Returns control space field from the physical space field using the inverse operator. This method needs to compute the inverse of the matrix used in ForwardFilterField to compute the UnfilteredField of the physical field. Args: - physical_field (ContainerExpressionTypes): Physical field. + physical_field (Kratos.TensorAdaptors.DoubleTensorAdaptor): Physical field. Returns: - ContainerExpressionTypes: Control field. + Kratos.TensorAdaptors.DoubleTensorAdaptor: Control field. """ pass diff --git a/applications/OptimizationApplication/python_scripts/filtering/filter_utils.py b/applications/OptimizationApplication/python_scripts/filtering/filter_utils.py index 89fb64f891ce..656c5e1d6ba9 100644 --- a/applications/OptimizationApplication/python_scripts/filtering/filter_utils.py +++ b/applications/OptimizationApplication/python_scripts/filtering/filter_utils.py @@ -2,7 +2,6 @@ import KratosMultiphysics as Kratos import KratosMultiphysics.OptimizationApplication as KratosOA -from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import ContainerExpressionTypes def FilterRadiusFactory(model_part: Kratos.ModelPart, container_type: Kratos.Globals.DataLocation, filter_radius_settings: Kratos.Parameters) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: if not filter_radius_settings.Has("filter_radius_type"): diff --git a/applications/OptimizationApplication/python_scripts/responses/response_function.py b/applications/OptimizationApplication/python_scripts/responses/response_function.py index 36588b70188d..c1c9ffaae2ee 100644 --- a/applications/OptimizationApplication/python_scripts/responses/response_function.py +++ b/applications/OptimizationApplication/python_scripts/responses/response_function.py @@ -75,21 +75,21 @@ def CalculateValue(self) -> float: pass @abstractmethod - def CalculateGradient(self, physical_variable_collective_expressions: 'dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]') -> None: + def CalculateGradient(self, physical_variable_combined_tensor_adaptor: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]') -> None: """Calculate gradient w.r.t. given physical variables. - This method should always calculate the sensitivities w.r.t. requested physical variables on the given container expressions - in the collective expression. An error should be thrown if sensitivitiy computation w.r.t. one or more given physical variables + This method should always calculate the sensitivities w.r.t. requested physical variables on the given @ref Kratos::TensorAdaptor + in the @ref Kratos::CombinedTensorAdaptor. An error should be thrown if sensitivitiy computation w.r.t. one or more given physical variables are not implemented. This method should always calculate the sensitivities assuming the domain has changed. - physical_variable_collective_expressions is a map of physical variables, and their domains. The domains are represented by a CollectiveExpression - which contains list of empty ContainerExpression. Each empty ContainerExpression contains details of the model part's nodes/conditions/element/properties + physical_variable_combined_tensor_adaptor is a map of physical variables, and their domains. The domains are represented by a @ref Kratos::CombinedTensorAdaptor + which contains list of empty @ref Kratos::TensorAdaptor. Each empty Kratos::TensorAdaptor contains details of the model part's nodes/conditions/element/properties container for which the sensitivities w.r.t. physical variable requested. Args: - physical_variable_collective_expressions (dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]): Output containing calculated sensitivities w.r.t. requested physical variables. + physical_variable_combined_tensor_adaptor (dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]): Output containing calculated sensitivities w.r.t. requested physical variables. """ pass diff --git a/applications/OptimizationApplication/python_scripts/responses/response_routine.py b/applications/OptimizationApplication/python_scripts/responses/response_routine.py index cb1304857eef..7dbab5981cba 100644 --- a/applications/OptimizationApplication/python_scripts/responses/response_routine.py +++ b/applications/OptimizationApplication/python_scripts/responses/response_routine.py @@ -4,7 +4,7 @@ from KratosMultiphysics.OptimizationApplication.responses.response_function import ResponseFunction from KratosMultiphysics.OptimizationApplication.controls.master_control import MasterControl from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes -import math +import math, numpy class ResponseRoutine: """A class which adds optimization-specific utilities to simplify routines @@ -18,7 +18,7 @@ def __init__(self, master_control: MasterControl, response: ResponseFunction) -> self.__response = response self.__response_value = None self.__contributing_controls_list: 'list[Control]' = [] - self.__required_physical_gradients: 'dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]' = {} + self.__required_physical_gradients: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]' = {} def GetMasterControl(self) -> MasterControl: return self.__master_control @@ -31,7 +31,7 @@ def Initialize(self): """ # create the required physical control fields to compute gradients self.__response.Initialize() - self.__required_physical_gradients = self.__master_control.GetPhysicalKratosVariableCollectiveExpressionsMap() + self.__required_physical_gradients = self.__master_control.GetPhysicalKratosVariableCombinedTensorAdaptorsMap() # now check which are the dependent physical space variables for the response, if not then remove # that variable @@ -47,15 +47,11 @@ def Initialize(self): for control in self.__master_control.GetListOfControls(): # check whether control has keys given by required gradients if set(control.GetPhysicalKratosVariables()).intersection(self.__required_physical_gradients.keys()): - # check whether there is an intersection of model parts between response influential domain and control domain. - checked_model_part: Kratos.ModelPart = self.__response.GetInfluencingModelPart() - - if Kratos.ModelPartOperationUtilities.HasIntersection([checked_model_part, control.GetEmptyField().GetModelPart()]): - self.__contributing_controls_list.append(control) + self.__contributing_controls_list.append(control) if not self.__contributing_controls_list: raise RuntimeError(f"The controls does not have any influence over the response {self.GetResponseName()}.") - + self.my_current_control_field = self.__master_control.GetEmptyField() def Check(self): @@ -70,7 +66,7 @@ def GetResponseName(self): def GetReponse(self) -> ResponseFunction: return self.__response - def CalculateValue(self, control_field: KratosOA.CollectiveExpression) -> float: + def CalculateValue(self, control_field: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor) -> float: """Calculates the value of the response. This method updates the design with the provided control field. If a control field is updated @@ -78,7 +74,7 @@ def CalculateValue(self, control_field: KratosOA.CollectiveExpression) -> float: value is returned. Args: - control_field (KratosOA.CollectiveExpression): Control field of the new design. + control_field (Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor): Control field of the new design. Returns: float: Response value. @@ -86,23 +82,29 @@ def CalculateValue(self, control_field: KratosOA.CollectiveExpression) -> float: # update using the master control and get updated states. self.__master_control.Update(control_field) compute_response_value_flag = False + if self.__response_value is None: - self.my_current_control_field = control_field.Clone() - if not math.isclose(KratosOA.ExpressionUtils.NormInf(self.my_current_control_field), 0.0, abs_tol=1e-16): - rel_diff = (self.my_current_control_field - control_field) / KratosOA.ExpressionUtils.NormInf(self.my_current_control_field) + self.my_current_control_field = Kratos.TensorAdaptors.DoubleTensorAdaptor(control_field) + + if not math.isclose(numpy.linalg.norm(self.my_current_control_field.data, ord="inf"), 0.0, abs_tol=1e-16): + rel_diff = (self.my_current_control_field.data - control_field.data) / numpy.linalg.norm(self.my_current_control_field.data, ord="inf") else: - rel_diff = (self.my_current_control_field - control_field) - norm = KratosOA.ExpressionUtils.NormInf(rel_diff) + rel_diff = (self.my_current_control_field.data - control_field.data) + + norm = numpy.linalg.norm(rel_diff, ord="inf") + if not math.isclose(norm, 0.0, abs_tol=1e-16): compute_response_value_flag = True - compute_response_value_flag = compute_response_value_flag or self.__response_value is None # TODO: In the case of having two analysis with the same mesh (model parts) for two different + + compute_response_value_flag = compute_response_value_flag or self.__response_value is None + # TODO: In the case of having two analysis with the same mesh (model parts) for two different # responses, we need to flag all the anayses which are affected by the control update_state # from the first call, otherwise the second call will not update anything, hence no execution # policies will be executed. # Example: Drag 1 with 10m/s, Drag 2 with 20 m/s using the same mesh and model parts with two # different analyses. - # # now set the response value in response data container + # now set the response value in response data container # if len(modified_model_parts) > 0: # # if there are any modified model parts, then this changes state of is_executed to false # # in the execution policies which has some intersection with the modified model parts. @@ -115,11 +117,11 @@ def CalculateValue(self, control_field: KratosOA.CollectiveExpression) -> float: Kratos.Logger.PrintInfo(f"The control field is not updated, hence the response value is not computed for {self.GetResponseName()}.") # Update current control field state - self.my_current_control_field = control_field.Clone() + self.my_current_control_field.data = control_field.data return self.__response_value - def CalculateGradient(self) -> KratosOA.CollectiveExpression: + def CalculateGradient(self) -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: """Returns Collective expression containing all the control space gradients for all control variable types (fields). Notes: @@ -127,7 +129,7 @@ def CalculateGradient(self) -> KratosOA.CollectiveExpression: 2. The gradients are computed with respect to updates from master control. Returns: - KratosOA.CollectiveExpression: Returns mapped gradients collective expression. + Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: Returns mapped gradients collective expression. """ # fills the proper physical gradients from the response self.__response.CalculateGradient(self.__required_physical_gradients) @@ -135,21 +137,21 @@ def CalculateGradient(self) -> KratosOA.CollectiveExpression: # calculate and return the control space gradients from respective controls self.__mapped_gradients = self.__master_control.MapGradient(self.__required_physical_gradients) return self.__mapped_gradients - + def GetMappedGradients(self): return self.__mapped_gradients - def GetRequiredPhysicalGradients(self) -> 'dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]': + def GetRequiredPhysicalGradients(self) -> 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]': """Returns required physical gradients by this response This method returns required physical gradients. The expressions may or not be empty field depending on CalculateGradient is called or not. Returns: - dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]: Required physical gradients. + dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]: Required physical gradients. """ return self.__required_physical_gradients - + def GetName(self): return self.GetReponse().GetName() diff --git a/applications/OptimizationApplication/python_scripts/utilities/helper_utilities.py b/applications/OptimizationApplication/python_scripts/utilities/helper_utilities.py index e2ea9473227a..b6c4359dfc02 100644 --- a/applications/OptimizationApplication/python_scripts/utilities/helper_utilities.py +++ b/applications/OptimizationApplication/python_scripts/utilities/helper_utilities.py @@ -4,7 +4,6 @@ import KratosMultiphysics as Kratos from KratosMultiphysics.kratos_utilities import GetListOfAvailableApplications from KratosMultiphysics.kratos_utilities import GetKratosMultiphysicsPath -from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import ContainerExpressionTypes def GetClassModuleFromKratos(full_class_name: str) -> str: sub_module_paths = full_class_name.split(".") @@ -39,15 +38,3 @@ def GetClassModuleFromKratos(full_class_name: str) -> str: def CallOnAll(list_of_objects: 'list[Any]', method: Any, *args, **kwargs): for obj in list_of_objects: getattr(obj, method.__name__)(*args, **kwargs) - -def IsSameContainerExpression(container_expression_1: ContainerExpressionTypes, container_expression_2: ContainerExpressionTypes) -> bool: - if container_expression_1.GetModelPart().FullName() != container_expression_2.GetModelPart().FullName(): - return False - - if type(container_expression_1) != type(container_expression_2): - return False - - return True - -def HasContainerExpression(container_expression: ContainerExpressionTypes, list_of_container_expressions: 'list[ContainerExpressionTypes]') -> bool: - return any([IsSameContainerExpression(container_expression, list_container_expression) for list_container_expression in list_of_container_expressions]) diff --git a/applications/OptimizationApplication/python_scripts/utilities/opt_projection.py b/applications/OptimizationApplication/python_scripts/utilities/opt_projection.py index 4ce89009667f..8dc79aa53aa7 100644 --- a/applications/OptimizationApplication/python_scripts/utilities/opt_projection.py +++ b/applications/OptimizationApplication/python_scripts/utilities/opt_projection.py @@ -7,7 +7,6 @@ import KratosMultiphysics as Kratos import KratosMultiphysics.OptimizationApplication as KratosOA from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem -from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import ContainerExpressionTypes class DesignVariableProjection(ABC): """Design variable projection methods to convert given x space values to given y space values @@ -29,38 +28,38 @@ def SetProjectionSpaces(self, x_space_values: 'list[float]', y_space_values: 'li pass @abstractmethod - def ProjectForward(self, x_values: ContainerExpressionTypes) -> ContainerExpressionTypes: + def ProjectForward(self, x_values: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: """Project x space values to y space Args: - x_values (ContainerExpressionTypes): x space values. + x_values (Kratos.TensorAdaptors.DoubleTensorAdaptor): x space values. Returns: - ContainerExpressionTypes: y space values. + Kratos.TensorAdaptors.DoubleTensorAdaptor: y space values. """ pass @abstractmethod - def ProjectBackward(self, y_values: ContainerExpressionTypes) -> ContainerExpressionTypes: + def ProjectBackward(self, y_values: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: """Project y space values to x space values Args: - y_values (ContainerExpressionTypes): y space values. + y_values (Kratos.TensorAdaptors.DoubleTensorAdaptor): y space values. Returns: - ContainerExpressionTypes: x space values. + Kratos.TensorAdaptors.DoubleTensorAdaptor: x space values. """ pass @abstractmethod - def ForwardProjectionGradient(self, x_values: ContainerExpressionTypes) -> ContainerExpressionTypes: + def ForwardProjectionGradient(self, x_values: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: """Computes the forward projected y space values' gradient w.r.t x space. Args: - x_values (ContainerExpressionTypes): x space values. + x_values (Kratos.TensorAdaptors.DoubleTensorAdaptor): x space values. Returns: - ContainerExpressionTypes: gradient of the y space values w.r.t. x space. + Kratos.TensorAdaptors.DoubleTensorAdaptor: gradient of the y space values w.r.t. x space. """ pass @@ -81,18 +80,18 @@ def SetProjectionSpaces(self, _: 'list[float]', __: 'list[float]') -> None: # not using any of the spaces provided. pass - def ProjectForward(self, x_values: ContainerExpressionTypes) -> ContainerExpressionTypes: + def ProjectForward(self, x_values: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: # returns the x_values since x and y are the same for IdentityProjection - return x_values.Clone() + return Kratos.TensorAdaptors.DoubleTensorAdaptor(x_values) - def ProjectBackward(self, y_values: ContainerExpressionTypes) -> ContainerExpressionTypes: + def ProjectBackward(self, y_values: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: # return the y_values since x and y are the same for Identity projection - return y_values.Clone() + return Kratos.TensorAdaptors.DoubleTensorAdaptor(y_values) - def ForwardProjectionGradient(self, x_values: ContainerExpressionTypes) -> ContainerExpressionTypes: - result = x_values.Clone() + def ForwardProjectionGradient(self, x_values: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + result = Kratos.TensorAdaptors.DoubleTensorAdaptor(x_values) # x = y, hence the gradients are 1.0 - Kratos.Expression.LiteralExpressionIO.SetData(result, 1.0) + result.data[:] = 1.0 return result def Update(self) -> None: @@ -117,26 +116,14 @@ def SetProjectionSpaces(self, x_space_values: 'list[float]', y_space_values: 'li self.x_space_values = x_space_values self.y_space_values = y_space_values - def ProjectForward(self, x_values: ContainerExpressionTypes) -> ContainerExpressionTypes: - ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(x_values.GetContainer(), Kratos.DoubleNDData(x_values.Evaluate()), copy=False) - result_ta = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectForward(ta, self.x_space_values, self.y_space_values, self.beta, self.penalty_factor) - result_exp = x_values.Clone() - Kratos.Expression.CArrayExpressionIO.Read(result_exp, result_ta.data) - return result_exp - - def ProjectBackward(self, y_values: ContainerExpressionTypes) -> ContainerExpressionTypes: - ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(y_values.GetContainer(), Kratos.DoubleNDData(y_values.Evaluate()), copy=False) - result_ta = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectBackward(ta, self.x_space_values, self.y_space_values, self.beta, self.penalty_factor) - result_exp = y_values.Clone() - Kratos.Expression.CArrayExpressionIO.Read(result_exp, result_ta.data) - return result_exp - - def ForwardProjectionGradient(self, x_values: ContainerExpressionTypes) -> ContainerExpressionTypes: - ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(x_values.GetContainer(), Kratos.DoubleNDData(x_values.Evaluate()), copy=False) - result_ta = KratosOA.ControlUtils.SigmoidalProjectionUtils.CalculateForwardProjectionGradient(ta, self.x_space_values, self.y_space_values, self.beta, self.penalty_factor) - result_exp = x_values.Clone() - Kratos.Expression.CArrayExpressionIO.Read(result_exp, result_ta.data) - return result_exp + def ProjectForward(self, x_values: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + return KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectForward(x_values, self.x_space_values, self.y_space_values, self.beta, self.penalty_factor) + + def ProjectBackward(self, y_values: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + return KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectBackward(y_values, self.x_space_values, self.y_space_values, self.beta, self.penalty_factor) + + def ForwardProjectionGradient(self, x_values: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + return KratosOA.ControlUtils.SigmoidalProjectionUtils.CalculateForwardProjectionGradient(x_values, self.x_space_values, self.y_space_values, self.beta, self.penalty_factor) def Update(self) -> None: pass @@ -169,26 +156,14 @@ def SetProjectionSpaces(self, x_space_values: 'list[float]', y_space_values: 'li self.x_space_values = x_space_values self.y_space_values = y_space_values - def ProjectForward(self, x_values: ContainerExpressionTypes) -> ContainerExpressionTypes: - ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(x_values.GetContainer(), Kratos.DoubleNDData(x_values.Evaluate()), copy=False) - result_ta = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectForward(ta, self.x_space_values, self.y_space_values, self.beta, self.penalty_factor) - result_exp = x_values.Clone() - Kratos.Expression.CArrayExpressionIO.Read(result_exp, result_ta.data) - return result_exp - - def ProjectBackward(self, y_values: ContainerExpressionTypes) -> ContainerExpressionTypes: - ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(y_values.GetContainer(), Kratos.DoubleNDData(y_values.Evaluate()), copy=False) - result_ta = KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectBackward(ta, self.x_space_values, self.y_space_values, self.beta, self.penalty_factor) - result_exp = y_values.Clone() - Kratos.Expression.CArrayExpressionIO.Read(result_exp, result_ta.data) - return result_exp - - def ForwardProjectionGradient(self, x_values: ContainerExpressionTypes) -> ContainerExpressionTypes: - ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(x_values.GetContainer(), Kratos.DoubleNDData(x_values.Evaluate()), copy=False) - result_ta = KratosOA.ControlUtils.SigmoidalProjectionUtils.CalculateForwardProjectionGradient(ta, self.x_space_values, self.y_space_values, self.beta, self.penalty_factor) - result_exp = x_values.Clone() - Kratos.Expression.CArrayExpressionIO.Read(result_exp, result_ta.data) - return result_exp + def ProjectForward(self, x_values: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + return KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectForward(x_values, self.x_space_values, self.y_space_values, self.beta, self.penalty_factor) + + def ProjectBackward(self, y_values: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + return KratosOA.ControlUtils.SigmoidalProjectionUtils.ProjectBackward(y_values, self.x_space_values, self.y_space_values, self.beta, self.penalty_factor) + + def ForwardProjectionGradient(self, x_values: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + return KratosOA.ControlUtils.SigmoidalProjectionUtils.CalculateForwardProjectionGradient(x_values, self.x_space_values, self.y_space_values, self.beta, self.penalty_factor) def Update(self) -> None: step = self.optimization_problem.GetStep() diff --git a/applications/OptimizationApplication/python_scripts/utilities/union_utilities.py b/applications/OptimizationApplication/python_scripts/utilities/union_utilities.py index 1245ed7ff71a..c7b819c84cb5 100644 --- a/applications/OptimizationApplication/python_scripts/utilities/union_utilities.py +++ b/applications/OptimizationApplication/python_scripts/utilities/union_utilities.py @@ -3,9 +3,4 @@ import KratosMultiphysics as Kratos # used union types for type hinting in python and for automated documentation generation -SupportedSensitivityFieldVariableTypes = Union[Kratos.DoubleVariable, Kratos.Array1DVariable3] - -ContainerExpressionTypes = Union[ - Kratos.Expression.NodalExpression, - Kratos.Expression.ConditionExpression, - Kratos.Expression.ElementExpression] \ No newline at end of file +SupportedSensitivityFieldVariableTypes = Union[Kratos.DoubleVariable, Kratos.Array1DVariable3] \ No newline at end of file diff --git a/applications/OptimizationApplication/tests/control/test_master_control.py b/applications/OptimizationApplication/tests/control/test_master_control.py index 9e8247945632..e22152c1252e 100644 --- a/applications/OptimizationApplication/tests/control/test_master_control.py +++ b/applications/OptimizationApplication/tests/control/test_master_control.py @@ -1,10 +1,10 @@ +import numpy import KratosMultiphysics as Kratos import KratosMultiphysics.OptimizationApplication as KratosOA import KratosMultiphysics.KratosUnittest as kratos_unittest from KratosMultiphysics.OptimizationApplication.controls.master_control import MasterControl from KratosMultiphysics.OptimizationApplication.controls.material.material_properties_control import MaterialPropertiesControl -from KratosMultiphysics.OptimizationApplication.utilities.helper_utilities import IsSameContainerExpression class TestMassterControl(kratos_unittest.TestCase): @classmethod @@ -64,61 +64,63 @@ def setUpClass(cls): def test_GetListOfControls(self): self.assertEqual([self.properties_control_1, self.properties_control_2, self.properties_control_3, self.properties_control_4], self.master_control.GetListOfControls()) - def test_GetPhysicalKratosVariableCollectiveExpressionsMap(self): - result = self.master_control.GetPhysicalKratosVariableCollectiveExpressionsMap() + def test_GetPhysicalKratosVariableCombinedTensorAdaptorsMap(self): + result = self.master_control.GetPhysicalKratosVariableCombinedTensorAdaptorsMap() self.assertEqual([Kratos.DENSITY, Kratos.THICKNESS], list(result.keys())) - density_collective_expression = result[Kratos.DENSITY] - density_container_expression_model_part_names = [] - for container_expression in density_collective_expression.GetContainerExpressions(): - self.assertTrue(isinstance(container_expression, Kratos.Expression.ElementExpression)) - density_container_expression_model_part_names.append(container_expression.GetModelPart().FullName()) + density_cta = result[Kratos.DENSITY] + density_ta_containers = [] + for ta in density_cta.GetTensorAdaptors(): + self.assertTrue(isinstance(ta.GetContainer(), Kratos.ElementsArray)) + density_ta_containers.append(ta.GetContainer()) self.assertEqual( - ["test1", "test2", "test3"], - density_container_expression_model_part_names) + [self.model["test1"].Elements, self.model["test2"].Elements, self.model["test3"].Elements], + density_ta_containers) - thickness_collective_expression = result[Kratos.THICKNESS] - thickness_container_expression_model_part_names = [] - for container_expression in thickness_collective_expression.GetContainerExpressions(): - self.assertTrue(isinstance(container_expression, Kratos.Expression.ElementExpression)) - thickness_container_expression_model_part_names.append(container_expression.GetModelPart().FullName()) + thickness_ta = result[Kratos.THICKNESS] + thickness_containers = [] + for ta in thickness_ta.GetTensorAdaptors(): + self.assertTrue(isinstance(ta.GetContainer(), Kratos.ElementsArray)) + thickness_containers.append(ta.GetContainer()) self.assertEqual( - ["test3"], - thickness_container_expression_model_part_names) + [self.model["test3"].Elements], + thickness_containers) def test_GetEmptyField(self): empty_control_fields = self.master_control.GetEmptyField() - container_expression_model_part_names = [] - for container_expression in empty_control_fields.GetContainerExpressions(): - self.assertTrue(isinstance(container_expression, Kratos.Expression.ElementExpression)) - self.assertEqual(Kratos.Expression.Utils.NormInf(container_expression), 0.0) - container_expression_model_part_names.append(container_expression.GetModelPart().FullName()) + containers = [] + for ta in empty_control_fields.GetTensorAdaptors(): + self.assertTrue(isinstance(ta.GetContainer(), Kratos.ElementsArray)) + self.assertEqual(numpy.linalg.norm(ta.data), 0.0) + containers.append(ta.GetContainer()) self.assertEqual( - ["test1", "test2", "test3", "test3"], - container_expression_model_part_names) + [self.model["test1"].Elements, self.model["test2"].Elements, self.model["test3"].Elements, self.model["test3"].Elements], + containers) def test_MapGradient(self): - result = self.master_control.GetPhysicalKratosVariableCollectiveExpressionsMap() + result = self.master_control.GetPhysicalKratosVariableCombinedTensorAdaptorsMap() mapped_gradients = self.master_control.MapGradient(result) for i, control in enumerate(self.master_control.GetListOfControls()): - self.assertTrue(IsSameContainerExpression(mapped_gradients.GetContainerExpressions()[i], control.GetEmptyField())) + self.assertTrue(mapped_gradients.GetTensorAdaptors()[i].GetContainer(), control.GetEmptyField().GetContainer()) # now check without any gradients so the master control should fill them with zeros. mapped_gradients = self.master_control.MapGradient({}) for i, control in enumerate(self.master_control.GetListOfControls()): - mapped_expression = mapped_gradients.GetContainerExpressions()[i] - self.assertTrue(IsSameContainerExpression(mapped_expression, control.GetEmptyField())) - self.assertEqual(Kratos.Expression.Utils.NormInf(mapped_expression), 0.0) + mapped_ta = mapped_gradients.GetTensorAdaptors()[i] + self.assertTrue(mapped_ta.GetContainer(), control.GetEmptyField().GetContainer()) + self.assertEqual(numpy.linalg.norm(mapped_ta.data), 0.0) def test_Update(self): update = self.master_control.GetEmptyField() # assigning density for all the mapped gradients - KratosOA.CollectiveExpressionIO.Read(update, KratosOA.CollectiveExpressionIO.PropertiesVariable(Kratos.DENSITY)) + for ta in update.GetTensorAdaptors(): + KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(ta, Kratos.DENSITY, copy=False).CollectData() + update.CollectData() # now updating density should not do anything for density controls, but thickness should be updated # checking for that @@ -129,7 +131,8 @@ def test_Update(self): else: self.assertFalse(v) - update *= 2 + update.data[:] *= 2.0 + update.StoreData() # now everything should be updated updated_status = self.master_control.Update(update) self.assertTrue(all(updated_status.values())) diff --git a/applications/OptimizationApplication/tests/filtering/explicit_filters_tests.py b/applications/OptimizationApplication/tests/filtering/explicit_filters_tests.py index b6db82f7b260..452b2b782db7 100644 --- a/applications/OptimizationApplication/tests/filtering/explicit_filters_tests.py +++ b/applications/OptimizationApplication/tests/filtering/explicit_filters_tests.py @@ -174,16 +174,17 @@ def setUpClass(cls) -> None: cls.optimization_problem = OptimizationProblem(0) - cls.initial_nodal_pos = Kratos.Expression.NodalExpression(cls.model_part) - Kratos.Expression.NodalPositionExpressionIO.Read(cls.initial_nodal_pos, Kratos.Configuration.Initial) + cls.initial_nodal_pos = Kratos.TensorAdaptors.NodePositionTensorAdaptor(cls.model_part.Nodes, Kratos.Configuration.Initial) + cls.initial_nodal_pos.CollectData() + cls.filter_data = ComponentDataView("test", cls.optimization_problem) cls.filter_data.SetDataBuffer(1) cls.vtu_output = Kratos.VtuOutput(cls.model_part, binary_output=Kratos.VtuOutput.ASCII, precision=6) def setUp(self) -> None: - Kratos.Expression.NodalPositionExpressionIO.Write(self.initial_nodal_pos, Kratos.Configuration.Initial) - Kratos.Expression.NodalPositionExpressionIO.Write(self.initial_nodal_pos, Kratos.Configuration.Current) + Kratos.TensorAdaptors.NodePositionTensorAdaptor(self.initial_nodal_pos, Kratos.Configuration.Initial, copy=False).StoreData() + Kratos.TensorAdaptors.NodePositionTensorAdaptor(self.initial_nodal_pos, Kratos.Configuration.Current, copy=False).StoreData() def test_FilterCosine(self): self.__RunTestCase("cosine", "cosine", "explicit_filter_reference_cosine.vtu") @@ -235,23 +236,34 @@ def __RunTestCase(self, filter_function_type: str, damping_function_type: str, r vm_filter.SetComponentDataView(ComponentDataView("test", self.optimization_problem)) vm_filter.Initialize() - nodal_neighbours = Kratos.Expression.NodalExpression(self.model_part) - KratosOA.ExpressionUtils.ComputeNumberOfNeighbourElements(nodal_neighbours) + nodal_neighbours = Kratos.TensorAdaptors.NodalNeighbourCountTensorAdaptor(self.model_part.Nodes, self.model_part.Elements) + nodal_neighbours.CollectData() + + nodal_neighbours_exp = Kratos.Expression.NodalExpression(self.model_part) + KratosOA.ExpressionUtils.ComputeNumberOfNeighbourElements(nodal_neighbours_exp) step_size = 5e-2 for i in range(10): Kratos.NormalCalculationUtils().CalculateNormalsInElements(self.model_part, Kratos.NORMAL) - element_exp = Kratos.Expression.ElementExpression(self.model_part) - Kratos.Expression.VariableExpressionIO.Read(element_exp, Kratos.NORMAL) - domain_size_exp = Kratos.Expression.ElementExpression(self.model_part) - Kratos.Expression.DomainSizeExpressionIO.Read(domain_size_exp) - physical_element_gradient = Kratos.Expression.Utils.Scale(element_exp, domain_size_exp) + element_ta = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Elements, Kratos.NORMAL) + element_ta.CollectData() + + domain_size_ta = Kratos.TensorAdaptors.GeometryMetricsTensorAdaptor(self.model_part.Elements, Kratos.TensorAdaptors.GeometryMetricsTensorAdaptor.DomainSize) + domain_size_ta.CollectData() + + physical_element_gradient = Kratos.TensorAdaptors.DoubleTensorAdaptor(element_ta) + physical_element_gradient.data = element_ta.data * domain_size_ta.data[:, None] # row wise scaling - physical_space_gradient = Kratos.Expression.NodalExpression(self.model_part) - KratosOA.ExpressionUtils.MapContainerVariableToNodalVariable(physical_space_gradient, physical_element_gradient, nodal_neighbours) + physical_element_gradient_exp = Kratos.Expression.ElementExpression(self.model_part) + Kratos.Expression.CArrayExpressionIO.Read(physical_element_gradient_exp, physical_element_gradient.data) + physical_space_gradient_exp = Kratos.Expression.NodalExpression(self.model_part) + KratosOA.ExpressionUtils.MapContainerVariableToNodalVariable(physical_space_gradient_exp, physical_element_gradient_exp, nodal_neighbours_exp) + physical_space_gradient = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, Kratos.NORMAL) + physical_space_gradient.data[:] = physical_space_gradient_exp.Evaluate() control_space_gradient = vm_filter.BackwardFilterField(physical_space_gradient) - control_update = control_space_gradient * (step_size / Kratos.Expression.Utils.NormInf(control_space_gradient)) + control_update = Kratos.TensorAdaptors.DoubleTensorAdaptor(control_space_gradient) + control_update.data = control_space_gradient.data * (step_size / numpy.max(numpy.abs(control_space_gradient.data))) physical_update = vm_filter.ForwardFilterField(control_update) # Purposefully left out for debugging if required. @@ -263,10 +275,15 @@ def __RunTestCase(self, filter_function_type: str, damping_function_type: str, r # self.vtu_output.PrintOutput(f"output_{i+1}") # update the mesh - nodal_coords = Kratos.Expression.NodalExpression(self.model_part) - Kratos.Expression.NodalPositionExpressionIO.Read(nodal_coords, Kratos.Configuration.Initial) - Kratos.Expression.NodalPositionExpressionIO.Write(nodal_coords + physical_update, Kratos.Configuration.Initial) - Kratos.Expression.NodalPositionExpressionIO.Write(nodal_coords + physical_update, Kratos.Configuration.Current) + nodal_coords_initial = Kratos.TensorAdaptors.NodePositionTensorAdaptor(self.model_part.Nodes, Kratos.Configuration.Initial) + nodal_coords_initial.CollectData() + nodal_coords_initial.data += physical_update.data + nodal_coords_initial.StoreData() + + nodal_coords_current = Kratos.TensorAdaptors.NodePositionTensorAdaptor(self.model_part.Nodes, Kratos.Configuration.Current) + nodal_coords_current.CollectData() + nodal_coords_current.data += physical_update.data + nodal_coords_current.StoreData() vm_filter.Update() diff --git a/applications/OptimizationApplication/tests/test_component_data_view.py b/applications/OptimizationApplication/tests/test_component_data_view.py index 430653d0bc18..85cc63cb42bc 100644 --- a/applications/OptimizationApplication/tests/test_component_data_view.py +++ b/applications/OptimizationApplication/tests/test_component_data_view.py @@ -24,7 +24,7 @@ def GetInfluencingModelPart(self) -> Kratos.ModelPart: return None def CalculateValue(self) -> float: return 0.0 - def CalculateGradient(self, _: 'dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]') -> None: + def CalculateGradient(self, _: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]') -> None: return None @classmethod diff --git a/applications/OptimizationApplication/tests/test_design_variable_projection.py b/applications/OptimizationApplication/tests/test_design_variable_projection.py index e179f88ca357..145936bbefed 100644 --- a/applications/OptimizationApplication/tests/test_design_variable_projection.py +++ b/applications/OptimizationApplication/tests/test_design_variable_projection.py @@ -16,8 +16,8 @@ def setUpClass(cls): for i in range(10): cls.test_model_part.CreateNewNode(i + 1, i, i + 1,0.0) - cls.position = Kratos.Expression.NodalExpression(cls.test_model_part) - Kratos.Expression.NodalPositionExpressionIO.Read(cls.position, Kratos.Configuration.Current) + cls.position = Kratos.TensorAdaptors.NodePositionTensorAdaptor(cls.test_model_part.Nodes, Kratos.Configuration.Current) + cls.position.CollectData() cls.optimization_problem = OptimizationProblem() parameters = Kratos.Parameters("""{ @@ -28,15 +28,15 @@ def setUpClass(cls): def test_ProjectBackward(self): result = self.projection.ProjectBackward(self.position) - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result - self.position), 0.0) + self.assertAlmostEqual(numpy.linalg.norm(result.data - self.position.data), 0.0) def test_ProjectForward(self): result = self.projection.ProjectForward(self.position) - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result - self.position), 0.0) + self.assertAlmostEqual(numpy.linalg.norm(result.data - self.position.data), 0.0) def test_ForwardProjectionGradient(self): result = self.projection.ForwardProjectionGradient(self.position) - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result), numpy.sqrt(self.test_model_part.NumberOfNodes())) + self.assertAlmostEqual(numpy.linalg.norm(result.data), numpy.sqrt(self.test_model_part.NumberOfNodes() * 3)) class TestSigmoidalDesignVariableProjection(kratos_unittest.TestCase): @@ -50,8 +50,8 @@ def setUpClass(cls): for i in range(10): cls.test_model_part.CreateNewNode(i + 1, i * 4, i * 3, i * 2) - cls.position = Kratos.Expression.NodalExpression(cls.test_model_part) - Kratos.Expression.NodalPositionExpressionIO.Read(cls.position, Kratos.Configuration.Current) + cls.position = Kratos.TensorAdaptors.NodePositionTensorAdaptor(cls.test_model_part.Nodes, Kratos.Configuration.Current) + cls.position.CollectData() cls.optimization_problem = OptimizationProblem() parameters = Kratos.Parameters("""{ @@ -64,15 +64,15 @@ def setUpClass(cls): def test_ProjectBackward(self): result = self.projection.ProjectBackward(self.position) - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result - self.position), 83.57033231673704) + self.assertAlmostEqual(numpy.linalg.norm(result.data - self.position.data), 83.57033231673704) def test_ProjectForward(self): result = self.projection.ProjectForward(self.position) - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result - self.position), 9874.416742272824) + self.assertAlmostEqual(numpy.linalg.norm(result.data - self.position.data), 9874.416742272824) def test_ForwardProjectionGradient(self): result = self.projection.ForwardProjectionGradient(self.position) - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result), 1111.1477428336996) + self.assertAlmostEqual(numpy.linalg.norm(result.data), 1111.1477428336996) class TestAdaptiveSigmoidalDesignVariableProjection(kratos_unittest.TestCase): @classmethod @@ -85,8 +85,8 @@ def setUpClass(cls): for i in range(10): cls.test_model_part.CreateNewNode(i + 1, i * 4, i * 3, i * 2) - cls.position = Kratos.Expression.NodalExpression(cls.test_model_part) - Kratos.Expression.NodalPositionExpressionIO.Read(cls.position, Kratos.Configuration.Current) + cls.position = Kratos.TensorAdaptors.NodePositionTensorAdaptor(cls.test_model_part.Nodes, Kratos.Configuration.Current) + cls.position.CollectData() cls.parameters = Kratos.Parameters("""{ "type" : "adaptive_sigmoidal_projection", @@ -106,25 +106,25 @@ def test_ProjectBackward(self): optimization_problem.AdvanceStep() result = projection.ProjectBackward(self.position) projection.Update() - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result - self.position), 83.57033231673704) + self.assertAlmostEqual(numpy.linalg.norm(result.data - self.position.data), 83.57033231673704) for i in range(5, 10): optimization_problem.AdvanceStep() result = projection.ProjectBackward(self.position) projection.Update() - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result - self.position), 82.98662649690897) + self.assertAlmostEqual(numpy.linalg.norm(result.data - self.position.data), 82.98662649690897) for i in range(10, 15): optimization_problem.AdvanceStep() result = projection.ProjectBackward(self.position) projection.Update() - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result - self.position), 82.5032449721012) + self.assertAlmostEqual(numpy.linalg.norm(result.data - self.position.data), 82.5032449721012) for i in range(15, 50): optimization_problem.AdvanceStep() result = projection.ProjectBackward(self.position) projection.Update() - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result - self.position), 82.40690497800159) + self.assertAlmostEqual(numpy.linalg.norm(result.data - self.position.data), 82.40690497800159) def test_ProjectForward(self): optimization_problem = OptimizationProblem() @@ -135,25 +135,25 @@ def test_ProjectForward(self): optimization_problem.AdvanceStep() result = projection.ProjectForward(self.position) projection.Update() - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result - self.position), 9874.416742272824) + self.assertAlmostEqual(numpy.linalg.norm(result.data - self.position.data), 9874.416742272824) for i in range(5, 10): optimization_problem.AdvanceStep() result = projection.ProjectForward(self.position) projection.Update() - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result - self.position), 9890.97484074556) + self.assertAlmostEqual(numpy.linalg.norm(result.data - self.position.data), 9890.97484074556) for i in range(10, 15): optimization_problem.AdvanceStep() result = projection.ProjectForward(self.position) projection.Update() - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result - self.position), 9905.434754063906) + self.assertAlmostEqual(numpy.linalg.norm(result.data - self.position.data), 9905.434754063906) for i in range(15, 50): optimization_problem.AdvanceStep() result = projection.ProjectForward(self.position) projection.Update() - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result - self.position), 9908.261739693658) + self.assertAlmostEqual(numpy.linalg.norm(result.data - self.position.data), 9908.261739693658) def test_ForwardProjectionGradient(self): optimization_problem = OptimizationProblem() @@ -164,25 +164,25 @@ def test_ForwardProjectionGradient(self): optimization_problem.AdvanceStep() result = projection.ForwardProjectionGradient(self.position) projection.Update() - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result - self.position), 1108.2457599723648) + self.assertAlmostEqual(numpy.linalg.norm(result.data - self.position.data), 1108.2457599723648) for i in range(5, 10): optimization_problem.AdvanceStep() result = projection.ForwardProjectionGradient(self.position) projection.Update() - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result - self.position), 966.0580001392216) + self.assertAlmostEqual(numpy.linalg.norm(result.data - self.position.data), 966.0580001392216) for i in range(10, 15): optimization_problem.AdvanceStep() result = projection.ForwardProjectionGradient(self.position) projection.Update() - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result - self.position), 765.7187019597883) + self.assertAlmostEqual(numpy.linalg.norm(result.data - self.position.data), 765.7187019597883) for i in range(15, 50): optimization_problem.AdvanceStep() result = projection.ForwardProjectionGradient(self.position) projection.Update() - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(result - self.position), 716.3046437643214) + self.assertAlmostEqual(numpy.linalg.norm(result.data - self.position.data), 716.3046437643214) if __name__ == "__main__": kratos_unittest.main() \ No newline at end of file diff --git a/applications/OptimizationApplication/tests/test_optimization_utils.py b/applications/OptimizationApplication/tests/test_optimization_utils.py index c2951fee99ec..9dec93cd5817 100644 --- a/applications/OptimizationApplication/tests/test_optimization_utils.py +++ b/applications/OptimizationApplication/tests/test_optimization_utils.py @@ -94,10 +94,9 @@ def create_properties(properties_id: int) -> Kratos.Properties: KratosOA.OptimizationUtils.CreateEntitySpecificPropertiesForContainer(model_part, model_part.Elements, False) - values = numpy.arange(50, dtype=numpy.float64) - expression = Kratos.Expression.ElementExpression(model_part) - Kratos.Expression.CArrayExpressionIO.Read(expression, values) - KratosOA.PropertiesVariableExpressionIO.Write(expression, Kratos.YOUNG_MODULUS) + ta = KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(model_part.Elements, Kratos.YOUNG_MODULUS) + ta.data[:] = numpy.arange(50, dtype=numpy.float64) + ta.StoreData() for element in model_part.Elements: self.assertEqual(element.Properties.Id, element.Id + 8) @@ -131,10 +130,9 @@ def create_properties(properties_id: int) -> Kratos.Properties: KratosOA.OptimizationUtils.CreateEntitySpecificPropertiesForContainer(model_part, model_part.Elements, True) - values = numpy.arange(50, dtype=numpy.float64) - expression = Kratos.Expression.ElementExpression(model_part) - Kratos.Expression.CArrayExpressionIO.Read(expression, values) - KratosOA.PropertiesVariableExpressionIO.Write(expression, Kratos.YOUNG_MODULUS) + ta = KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(model_part.Elements, Kratos.YOUNG_MODULUS) + ta.data[:] = numpy.arange(50, dtype=numpy.float64) + ta.StoreData() def check_properties_value_recursively(properties: Kratos.Properties, value: float): self.assertEqual(properties[Kratos.YOUNG_MODULUS], value) @@ -169,5 +167,123 @@ def check_properties_value_recursively(properties: Kratos.Properties, value: flo for element in model_part.Elements: check_properties_value_recursively(element.Properties, element.Id - 1) + def test_MapConditionDataToNodalData(self): + for entity in self.model_part.Conditions: + entity.SetValue(Kratos.VELOCITY, Kratos.Array3([entity.Id, entity.Id + 1, entity.Id + 3])) + entity.SetValue(Kratos.PRESSURE, entity.Id + 4) + + condition_ta_v = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Conditions, Kratos.VELOCITY) + condition_ta_v.CollectData() + condition_ta_p = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Conditions, Kratos.PRESSURE) + condition_ta_p.CollectData() + + nodal_ta_v = KratosOA.OptimizationUtils.MapContainerDataToNodalData(condition_ta_v, self.model_part.Nodes) + nodal_ta_p = KratosOA.OptimizationUtils.MapContainerDataToNodalData(condition_ta_p, self.model_part.Nodes) + + self.assertVectorAlmostEqual(nodal_ta_v.data.shape, [self.model_part.NumberOfNodes(), 3]) + self.assertVectorAlmostEqual(nodal_ta_p.data.shape, [self.model_part.NumberOfNodes()]) + + Kratos.VariableUtils().SetNonHistoricalVariableToZero(Kratos.DENSITY, self.model_part.Nodes) + Kratos.VariableUtils().SetNonHistoricalVariableToZero(Kratos.ACCELERATION, self.model_part.Nodes) + for entity in self.model_part.Conditions: + for node in entity.GetGeometry(): + node[Kratos.ACCELERATION] += entity[Kratos.VELOCITY] / len(entity.GetGeometry()) + node[Kratos.DENSITY] += entity[Kratos.PRESSURE] / len(entity.GetGeometry()) + + for i, node in enumerate(self.model_part.Nodes): + self.assertVectorAlmostEqual(nodal_ta_v.data[i, :], node[Kratos.ACCELERATION]) + self.assertAlmostEqual(nodal_ta_p.data[i], node[Kratos.DENSITY]) + + def test_MapElementDataToNodalData(self): + for entity in self.model_part.Elements: + entity.SetValue(Kratos.VELOCITY, Kratos.Array3([entity.Id, entity.Id + 1, entity.Id + 3])) + entity.SetValue(Kratos.PRESSURE, entity.Id + 4) + + condition_ta_v = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Elements, Kratos.VELOCITY) + condition_ta_v.CollectData() + condition_ta_p = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Elements, Kratos.PRESSURE) + condition_ta_p.CollectData() + + nodal_ta_v = KratosOA.OptimizationUtils.MapContainerDataToNodalData(condition_ta_v, self.model_part.Nodes) + nodal_ta_p = KratosOA.OptimizationUtils.MapContainerDataToNodalData(condition_ta_p, self.model_part.Nodes) + + self.assertVectorAlmostEqual(nodal_ta_v.data.shape, [self.model_part.NumberOfNodes(), 3]) + self.assertVectorAlmostEqual(nodal_ta_p.data.shape, [self.model_part.NumberOfNodes()]) + + Kratos.VariableUtils().SetNonHistoricalVariableToZero(Kratos.DENSITY, self.model_part.Nodes) + Kratos.VariableUtils().SetNonHistoricalVariableToZero(Kratos.ACCELERATION, self.model_part.Nodes) + for entity in self.model_part.Elements: + for node in entity.GetGeometry(): + node[Kratos.ACCELERATION] += entity[Kratos.VELOCITY] / len(entity.GetGeometry()) + node[Kratos.DENSITY] += entity[Kratos.PRESSURE] / len(entity.GetGeometry()) + + for i, node in enumerate(self.model_part.Nodes): + self.assertVectorAlmostEqual(nodal_ta_v.data[i, :], node[Kratos.ACCELERATION]) + self.assertAlmostEqual(nodal_ta_p.data[i], node[Kratos.DENSITY]) + + def test_MapNodalDataToConditionData(self): + for node in self.model_part.Nodes: + node.SetValue(Kratos.VELOCITY, Kratos.Array3([node.Id, node.Id + 1, node.Id + 3])) + node.SetValue(Kratos.PRESSURE, node.Id + 4) + + nodal_ta_v = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, Kratos.VELOCITY) + nodal_ta_v.CollectData() + nodal_ta_p = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, Kratos.PRESSURE) + nodal_ta_p.CollectData() + + neighbour_count_ta = Kratos.TensorAdaptors.NodalNeighbourCountTensorAdaptor(self.model_part.Nodes, self.model_part.Conditions) + neighbour_count_ta.CollectData() + for i, node in enumerate(neighbour_count_ta.GetContainer()): + node[Kratos.YOUNG_MODULUS] = neighbour_count_ta.data[i] + + entity_ta_v = KratosOA.OptimizationUtils.MapNodalDataToContainerData(nodal_ta_v, self.model_part.Conditions, neighbour_count_ta) + entity_ta_p = KratosOA.OptimizationUtils.MapNodalDataToContainerData(nodal_ta_p, self.model_part.Conditions, neighbour_count_ta) + + self.assertVectorAlmostEqual(entity_ta_v.data.shape, [self.model_part.NumberOfConditions(), 3]) + self.assertVectorAlmostEqual(entity_ta_p.data.shape, [self.model_part.NumberOfConditions()]) + + Kratos.VariableUtils().SetNonHistoricalVariableToZero(Kratos.DENSITY, self.model_part.Conditions) + Kratos.VariableUtils().SetNonHistoricalVariableToZero(Kratos.ACCELERATION, self.model_part.Conditions) + for entity in self.model_part.Conditions: + for node in entity.GetGeometry(): + entity[Kratos.ACCELERATION] += node[Kratos.VELOCITY] / node[Kratos.YOUNG_MODULUS] + entity[Kratos.DENSITY] += node[Kratos.PRESSURE] / node[Kratos.YOUNG_MODULUS] + + for i, entity in enumerate(self.model_part.Conditions): + self.assertVectorAlmostEqual(entity_ta_v.data[i, :], entity[Kratos.ACCELERATION]) + self.assertAlmostEqual(entity_ta_p.data[i], entity[Kratos.DENSITY]) + + def test_MapNodalDataToElementData(self): + for node in self.model_part.Nodes: + node.SetValue(Kratos.VELOCITY, Kratos.Array3([node.Id, node.Id + 1, node.Id + 3])) + node.SetValue(Kratos.PRESSURE, node.Id + 4) + + nodal_ta_v = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, Kratos.VELOCITY) + nodal_ta_v.CollectData() + nodal_ta_p = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, Kratos.PRESSURE) + nodal_ta_p.CollectData() + + neighbour_count_ta = Kratos.TensorAdaptors.NodalNeighbourCountTensorAdaptor(self.model_part.Nodes, self.model_part.Elements) + neighbour_count_ta.CollectData() + for i, node in enumerate(neighbour_count_ta.GetContainer()): + node[Kratos.YOUNG_MODULUS] = neighbour_count_ta.data[i] + + entity_ta_v = KratosOA.OptimizationUtils.MapNodalDataToContainerData(nodal_ta_v, self.model_part.Elements, neighbour_count_ta) + entity_ta_p = KratosOA.OptimizationUtils.MapNodalDataToContainerData(nodal_ta_p, self.model_part.Elements, neighbour_count_ta) + + self.assertVectorAlmostEqual(entity_ta_v.data.shape, [self.model_part.NumberOfElements(), 3]) + self.assertVectorAlmostEqual(entity_ta_p.data.shape, [self.model_part.NumberOfElements()]) + + Kratos.VariableUtils().SetNonHistoricalVariableToZero(Kratos.DENSITY, self.model_part.Elements) + Kratos.VariableUtils().SetNonHistoricalVariableToZero(Kratos.ACCELERATION, self.model_part.Elements) + for entity in self.model_part.Elements: + for node in entity.GetGeometry(): + entity[Kratos.ACCELERATION] += node[Kratos.VELOCITY] / node[Kratos.YOUNG_MODULUS] + entity[Kratos.DENSITY] += node[Kratos.PRESSURE] / node[Kratos.YOUNG_MODULUS] + + for i, entity in enumerate(self.model_part.Elements): + self.assertVectorAlmostEqual(entity_ta_v.data[i, :], entity[Kratos.ACCELERATION]) + self.assertAlmostEqual(entity_ta_p.data[i], entity[Kratos.DENSITY]) + if __name__ == "__main__": kratos_unittest.main() \ No newline at end of file diff --git a/applications/OptimizationApplication/tests/test_response_utilities.py b/applications/OptimizationApplication/tests/test_response_utilities.py index b1c6febf2669..b344c034c4b9 100644 --- a/applications/OptimizationApplication/tests/test_response_utilities.py +++ b/applications/OptimizationApplication/tests/test_response_utilities.py @@ -39,7 +39,7 @@ def CalculateValue(self) -> float: self.calculate_value_calls += 1 return self.response_function.CalculateValue() - def CalculateGradient(self, physical_variable_collective_expressions: 'dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]') -> None: + def CalculateGradient(self, physical_variable_collective_expressions: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]') -> None: self.calculate_gradient_calls += 1 return self.response_function.CalculateGradient(physical_variable_collective_expressions) @@ -94,12 +94,12 @@ def __CheckGradients(self, sensitivity_variables: 'list[SupportedSensitivityFiel ref_value = analytical_lambda() self.assertAlmostEqual(ref_value, response_function.CalculateValue(), precision) - physical_variable_collective_expressions: 'dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]' = {} + physical_variable_collective_expressions: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]' = {} fd_gradients: 'dict[SupportedSensitivityFieldVariableTypes, list[float]]' = {} for sensitivity_variable in sensitivity_variables: - nodal_exp = Kratos.Expression.NodalExpression(self.model_part) - Kratos.Expression.LiteralExpressionIO.SetData(nodal_exp, 0.0) - physical_variable_collective_expressions[sensitivity_variable] = KratosOA.CollectiveExpression([nodal_exp]) + ta = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, sensitivity_variable) + ta.data[:] = 0.0 + physical_variable_collective_expressions[sensitivity_variable] = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([ta], perform_collect_data_recursively=False, perform_store_data_recursively=False) fd_gradients[sensitivity_variable] = [] response_function.CalculateGradient(physical_variable_collective_expressions) @@ -111,9 +111,9 @@ def __CheckGradients(self, sensitivity_variables: 'list[SupportedSensitivityFiel node.SetValue(sensitivity_variable, node.GetValue(sensitivity_variable) - delta) for sensitivity_variable in sensitivity_variables: - nodal_exp = Kratos.Expression.NodalExpression(self.model_part) - Kratos.Expression.CArrayExpressionIO.Read(nodal_exp, np.array(fd_gradients[sensitivity_variable], np.float64)) - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(nodal_exp - physical_variable_collective_expressions[sensitivity_variable].GetContainerExpressions()[0]), 0.0, precision) + ta = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, sensitivity_variable) + ta.data[:] = np.array(fd_gradients[sensitivity_variable], np.float64) + self.assertAlmostEqual(np.linalg.norm(ta.data - physical_variable_collective_expressions[sensitivity_variable].GetTensorAdaptors()[0].data, ord="inf"), 0.0, precision) def setUp(self) -> None: self.optimization_problem = OptimizationProblem() diff --git a/kratos/python/add_tensor_adaptors_to_python.cpp b/kratos/python/add_tensor_adaptors_to_python.cpp index 8cf8865b2b42..f7f4ea341d31 100644 --- a/kratos/python/add_tensor_adaptors_to_python.cpp +++ b/kratos/python/add_tensor_adaptors_to_python.cpp @@ -37,6 +37,7 @@ #include "tensor_adaptors/tensor_adaptor.h" #include "tensor_adaptors/variable_tensor_adaptor.h" #include "tensor_adaptors/nodal_neighbour_count_tensor_adaptor.h" +#include "tensor_adaptors/geometry_metrics_tensor_adaptor.h" // Include base h #include "add_tensor_adaptors_to_python.h" @@ -46,311 +47,294 @@ namespace Kratos::Python { namespace Detail { template -void AddBaseTensorAdaptor(pybind11::module &rModule, const std::string &rName) { - // add the base tensor adaptor - using tensor_adaptor = TensorAdaptor; - pybind11::class_( - rModule, (rName + "Adaptor").c_str()) - .def(pybind11::init::Pointer, const bool>(), - pybind11::arg("container"), pybind11::arg("nd_data"), - pybind11::arg("copy") = true) - .def(pybind11::init(), - pybind11::arg("tensor_adaptor"), pybind11::arg("copy") = true) - .def("Check", &tensor_adaptor::Check) - .def("CollectData", &tensor_adaptor::CollectData) - .def("StoreData", &tensor_adaptor::StoreData) - .def("GetContainer", &tensor_adaptor::GetContainer) - .def("HasContainer", &tensor_adaptor::HasContainer) - .def("Shape", &tensor_adaptor::Shape) - .def("DataShape", &tensor_adaptor::DataShape) - .def("Size", &tensor_adaptor::Size) - .def("__str__", PrintObject) - .def("ViewData", - [](tensor_adaptor &rSelf) { - return GetPybindArray(*rSelf.pGetStorage()); - }) - .def( - "SetData", - [](tensor_adaptor &rSelf, const pybind11::array &rArray) { - SetPybindArray(*rSelf.pGetStorage(), rArray); - }, - pybind11::arg("array").noconvert()) - .def_property( - "data", - [](tensor_adaptor &rSelf) { - return GetPybindArray(*rSelf.pGetStorage()); - }, - pybind11::cpp_function( - [](tensor_adaptor &rSelf, const pybind11::array &rArray) { - SetPybindArray(*rSelf.pGetStorage(), rArray); - }, - pybind11::arg("self"), - // no convert makes sure that the numpy arrays are - // not converted, hence nothing will be copied. numpy - // array will be passed as it is to the SetPybindArray - // method. - pybind11::arg("array").noconvert())); +void AddBaseTensorAdaptor( + pybind11::module& rModule, + const std::string& rName) +{ + // add the base tensor adaptor + using tensor_adaptor = TensorAdaptor; + pybind11::class_( + rModule, (rName + "Adaptor").c_str()) + .def(pybind11::init::Pointer, const bool>(), + pybind11::arg("container"), + pybind11::arg("nd_data"), + pybind11::arg("copy") = true) + .def(pybind11::init(), + pybind11::arg("tensor_adaptor"), + pybind11::arg("copy") = true) + .def("Check", &tensor_adaptor::Check) + .def("CollectData", &tensor_adaptor::CollectData) + .def("StoreData", &tensor_adaptor::StoreData) + .def("GetContainer", &tensor_adaptor::GetContainer) + .def("HasContainer", &tensor_adaptor::HasContainer) + .def("Shape", &tensor_adaptor::Shape) + .def("DataShape", &tensor_adaptor::DataShape) + .def("Size", &tensor_adaptor::Size) + .def("__str__", PrintObject) + .def("ViewData", [](tensor_adaptor& rSelf) { return GetPybindArray(*rSelf.pGetStorage()); }) + .def("SetData", [](tensor_adaptor& rSelf, const pybind11::array& rArray) { SetPybindArray(*rSelf.pGetStorage(), rArray); }, + pybind11::arg("array").noconvert()) + .def_property("data", + [](tensor_adaptor& rSelf) { + return GetPybindArray(*rSelf.pGetStorage()); + }, + pybind11::cpp_function( + [](tensor_adaptor& rSelf, const pybind11::array& rArray) { + SetPybindArray(*rSelf.pGetStorage(), rArray); + }, + pybind11::arg("self"), + // no convert makes sure that the numpy arrays are + // not converted, hence nothing will be copied. numpy + // array will be passed as it is to the SetPybindArray + // method. + pybind11::arg("array").noconvert())); } template -void AddCombinedTensorAdaptor(pybind11::module &rModule, - const std::string &rName) { - using combined_ta_type = CombinedTensorAdaptor; - pybind11::class_(rModule, rName.c_str()) - .def(pybind11::init< - const typename combined_ta_type::TensorAdaptorVectorType &, - const bool, const bool>(), - pybind11::arg("list_of_tensor_adaptors"), - pybind11::arg("perform_collect_data_recursively") = true, - pybind11::arg("perform_store_data_recursively") = - true) // reveling ctor - .def(pybind11::init< - const typename combined_ta_type::TensorAdaptorVectorType &, - const unsigned int, const bool, const bool>(), - pybind11::arg("list_of_tensor_adaptors"), pybind11::arg("axis"), - pybind11::arg("perform_collect_data_recursively") = true, - pybind11::arg("perform_store_data_recursively") = - true) // axis based ctor - .def(pybind11::init(), - pybind11::arg("list_of_tensor_adaptors"), - pybind11::arg("perform_collect_data_recursively") = true, - pybind11::arg("perform_store_data_recursively") = true, - pybind11::arg("copy") = true) - .def("GetTensorAdaptors", &combined_ta_type::GetTensorAdaptors); +void AddCombinedTensorAdaptor( + pybind11::module &rModule, + const std::string &rName) +{ + using combined_ta_type = CombinedTensorAdaptor; + pybind11::class_(rModule, rName.c_str()) + .def(pybind11::init(), + pybind11::arg("list_of_tensor_adaptors"), + pybind11::arg("perform_collect_data_recursively") = true, + pybind11::arg("perform_store_data_recursively") = true) // reveling ctor + .def(pybind11::init(), + pybind11::arg("list_of_tensor_adaptors"), pybind11::arg("axis"), + pybind11::arg("perform_collect_data_recursively") = true, + pybind11::arg("perform_store_data_recursively") = true) // axis based ctor + .def(pybind11::init(), + pybind11::arg("list_of_tensor_adaptors"), + pybind11::arg("perform_collect_data_recursively") = true, + pybind11::arg("perform_store_data_recursively") = true, + pybind11::arg("copy") = true) + .def("GetTensorAdaptors", &combined_ta_type::GetTensorAdaptors); } } // namespace Detail -void AddTensorAdaptorsToPython(pybind11::module &m) { - namespace py = pybind11; +void AddTensorAdaptorsToPython(pybind11::module& m) +{ + namespace py = pybind11; - auto tensor_adaptor_sub_module = m.def_submodule("TensorAdaptors"); - Detail::AddBaseTensorAdaptor(tensor_adaptor_sub_module, "BoolTensor"); - Detail::AddBaseTensorAdaptor(tensor_adaptor_sub_module, "IntTensor"); - Detail::AddBaseTensorAdaptor(tensor_adaptor_sub_module, - "DoubleTensor"); + auto tensor_adaptor_sub_module = m.def_submodule("TensorAdaptors"); + Detail::AddBaseTensorAdaptor(tensor_adaptor_sub_module, "BoolTensor"); + Detail::AddBaseTensorAdaptor(tensor_adaptor_sub_module, "IntTensor"); + Detail::AddBaseTensorAdaptor(tensor_adaptor_sub_module, "DoubleTensor"); - Detail::AddCombinedTensorAdaptor(tensor_adaptor_sub_module, - "BoolCombinedTensorAdaptor"); - Detail::AddCombinedTensorAdaptor(tensor_adaptor_sub_module, - "IntCombinedTensorAdaptor"); - Detail::AddCombinedTensorAdaptor(tensor_adaptor_sub_module, - "DoubleCombinedTensorAdaptor"); + Detail::AddCombinedTensorAdaptor(tensor_adaptor_sub_module, "BoolCombinedTensorAdaptor"); + Detail::AddCombinedTensorAdaptor(tensor_adaptor_sub_module, "IntCombinedTensorAdaptor"); + Detail::AddCombinedTensorAdaptor(tensor_adaptor_sub_module, "DoubleCombinedTensorAdaptor"); - py::class_( - tensor_adaptor_sub_module, "HistoricalVariableTensorAdaptor") - .def(py::init(), - py::arg("container"), py::arg("variable"), py::arg("step_index") = 0) - .def(py::init &, const int>(), - py::arg("container"), py::arg("variable"), py::arg("data_shape"), - py::arg("step_index") = 0) - .def(py::init(), - py::arg("tensor_adaptor"), py::arg("variable"), - py::arg("step_index") = 0, py::arg("copy") = true); + py::class_(tensor_adaptor_sub_module, "HistoricalVariableTensorAdaptor") + .def(py::init(), + py::arg("container"), + py::arg("variable"), + py::arg("step_index") = 0) + .def(py::init&, const int>(), + py::arg("container"), + py::arg("variable"), + py::arg("data_shape"), + py::arg("step_index") = 0) + .def(py::init(), + py::arg("tensor_adaptor"), + py::arg("variable"), + py::arg("step_index") = 0, + py::arg("copy") = true); - py::class_(tensor_adaptor_sub_module, - "VariableTensorAdaptor") - .def(py::init(), - py::arg("container"), py::arg("variable")) - .def(py::init &>(), - py::arg("container"), py::arg("variable"), py::arg("data_shape")) - .def(py::init(), - py::arg("container"), py::arg("variable")) - .def(py::init &>(), - py::arg("container"), py::arg("variable"), py::arg("data_shape")) - .def(py::init(), - py::arg("container"), py::arg("variable")) - .def(py::init &>(), - py::arg("container"), py::arg("variable"), py::arg("data_shape")) - .def(py::init(), - py::arg("container"), py::arg("variable")) - .def(py::init &>(), - py::arg("container"), py::arg("variable"), py::arg("data_shape")) - .def(py::init(), - py::arg("container"), py::arg("variable")) - .def(py::init &>(), - py::arg("container"), py::arg("variable"), py::arg("data_shape")) - .def(py::init(), - py::arg("container"), py::arg("variable")) - .def(py::init &>(), - py::arg("container"), py::arg("variable"), py::arg("data_shape")) - .def(py::init(), - py::arg("tensor_adaptor"), py::arg("variable"), - py::arg("copy") = true); + py::class_(tensor_adaptor_sub_module, "VariableTensorAdaptor") + .def(py::init(), + py::arg("container"), + py::arg("variable")) + .def(py::init&>(), + py::arg("container"), + py::arg("variable"), + py::arg("data_shape")) + .def(py::init(), + py::arg("container"), + py::arg("variable")) + .def(py::init&>(), + py::arg("container"), + py::arg("variable"), + py::arg("data_shape")) + .def(py::init(), + py::arg("container"), + py::arg("variable")) + .def(py::init&>(), + py::arg("container"), + py::arg("variable"), + py::arg("data_shape")) + .def(py::init(), + py::arg("container"), + py::arg("variable")) + .def(py::init&>(), + py::arg("container"), + py::arg("variable"), + py::arg("data_shape")) + .def(py::init(), + py::arg("container"), + py::arg("variable")) + .def(py::init&>(), + py::arg("container"), + py::arg("variable"), + py::arg("data_shape")) + .def(py::init(), + py::arg("container"), + py::arg("variable")) + .def(py::init&>(), + py::arg("container"), + py::arg("variable"), + py::arg("data_shape")) + .def(py::init(), + py::arg("tensor_adaptor"), + py::arg("variable"), + py::arg("copy") = true); - py::class_( - tensor_adaptor_sub_module, "GaussPointVariableTensorAdaptor") - .def(py::init(), - py::arg("container"), py::arg("variable"), py::arg("process_info")) - .def(py::init(), - py::arg("container"), py::arg("variable"), py::arg("process_info")) - .def(py::init(), - py::arg("tensor_adaptor"), py::arg("variable"), - py::arg("process_info"), py::arg("copy") = true); + py::class_(tensor_adaptor_sub_module, "GaussPointVariableTensorAdaptor") + .def(py::init(), + py::arg("container"), + py::arg("variable"), + py::arg("process_info")) + .def(py::init(), + py::arg("container"), + py::arg("variable"), + py::arg("process_info")) + .def(py::init(), + py::arg("tensor_adaptor"), + py::arg("variable"), + py::arg("process_info"), + py::arg("copy") = true); - py::class_(tensor_adaptor_sub_module, - "EquationIdsTensorAdaptor") - .def(py::init(), - py::arg("container"), py::arg("process_info")) - .def(py::init(), - py::arg("container"), py::arg("process_info")) - .def(py::init(), - py::arg("tensor_adaptor"), py::arg("process_info"), - py::arg("copy") = true); + py::class_(tensor_adaptor_sub_module, "EquationIdsTensorAdaptor") + .def(py::init(), + py::arg("container"), + py::arg("process_info")) + .def(py::init(), + py::arg("container"), + py::arg("process_info")) + .def(py::init(), + py::arg("tensor_adaptor"), + py::arg("process_info"), + py::arg("copy") = true); - py::class_(tensor_adaptor_sub_module, - "FlagsTensorAdaptor") - .def(py::init(), - py::arg("container"), py::arg("flag")) - .def(py::init(), - py::arg("container"), py::arg("flag")) - .def(py::init(), - py::arg("container"), py::arg("flag")) - .def(py::init(), - py::arg("tensor_adaptor"), py::arg("flag"), py::arg("copy") = true); + py::class_(tensor_adaptor_sub_module, "FlagsTensorAdaptor") + .def(py::init(), + py::arg("container"), + py::arg("flag")) + .def(py::init(), + py::arg("container"), + py::arg("flag")) + .def(py::init(), + py::arg("container"), + py::arg("flag")) + .def(py::init(), + py::arg("tensor_adaptor"), + py::arg("flag"), py::arg("copy") = true); - py::class_(tensor_adaptor_sub_module, - "NodePositionTensorAdaptor") - .def(py::init(), - py::arg("container"), py::arg("configuration")) - .def( - py::init &>(), - py::arg("container"), py::arg("configuration"), py::arg("data_shape")) - .def(py::init(), - py::arg("tensor_adaptor"), py::arg("configuration"), - py::arg("copy") = true); + py::class_(tensor_adaptor_sub_module, "NodePositionTensorAdaptor") + .def(py::init(), + py::arg("container"), + py::arg("configuration")) + .def(py::init&>(), + py::arg("container"), + py::arg("configuration"), + py::arg("data_shape")) + .def(py::init(), + py::arg("tensor_adaptor"), + py::arg("configuration"), + py::arg("copy") = true); + using GeometriesTensorAdaptorType = GeometriesTensorAdaptor; + py::class_ geometries_tensor_adaptor(tensor_adaptor_sub_module, "GeometriesTensorAdaptor"); - using GeometriesTensorAdaptorType = GeometriesTensorAdaptor; - py::class_ - geometries_tensor_adaptor(tensor_adaptor_sub_module, - "GeometriesTensorAdaptor"); + py::enum_(geometries_tensor_adaptor,"DatumType") + .value("ShapeFunctions", GeometriesTensorAdaptorType::DatumType::ShapeFunctions) + .value("ShapeFunctionDerivatives", GeometriesTensorAdaptorType::DatumType::ShapeFunctionDerivatives) + .value("Jacobians", GeometriesTensorAdaptorType::DatumType::Jacobians) + .value("IntegrationWeights", GeometriesTensorAdaptorType::DatumType::IntegrationWeights) + .export_values(); - py::enum_(geometries_tensor_adaptor, - "DatumType") - .value("ShapeFunctions", - GeometriesTensorAdaptorType::DatumType::ShapeFunctions) - .value("ShapeFunctionDerivatives", - GeometriesTensorAdaptorType::DatumType::ShapeFunctionDerivatives) - .value("Jacobians", GeometriesTensorAdaptorType::DatumType::Jacobians) - .value("IntegrationWeights", - GeometriesTensorAdaptorType::DatumType::IntegrationWeights) - .export_values(); + geometries_tensor_adaptor + .def(py::init(), + py::arg("container"), + py::arg("datum"), + py::arg("integration_method") = GeometryData::IntegrationMethod::NumberOfIntegrationMethods) + .def(py::init(), + py::arg("container"), + py::arg("datum"), + py::arg("integration_method") = GeometryData::IntegrationMethod::NumberOfIntegrationMethods) + .def(py::init(), + py::arg("container"), + py::arg("datum"), + py::arg("integration_method") = GeometryData::IntegrationMethod::NumberOfIntegrationMethods) + .def(py::init(), + py::arg("tensor_adaptor"), + py::arg("container"), + py::arg("datum"), + py::arg("integration_method"), + py::arg("copy") = true) + .def(py::init(), + py::arg("tensor_adaptor"), + py::arg("container"), + py::arg("datum"), + py::arg("integration_method"), + py::arg("copy") = true) + .def(py::init(), + py::arg("tensor_adaptor"), + py::arg("container"), + py::arg("datum"), + py::arg("integration_method"), + py::arg("copy") = true); - geometries_tensor_adaptor - .def(py::init(), - py::arg("container"), py::arg("datum"), - py::arg("integration_method") = - GeometryData::IntegrationMethod::NumberOfIntegrationMethods) - .def(py::init(), - py::arg("container"), py::arg("datum"), - py::arg("integration_method") = - GeometryData::IntegrationMethod::NumberOfIntegrationMethods) - .def(py::init(), - py::arg("container"), py::arg("datum"), - py::arg("integration_method") = - GeometryData::IntegrationMethod::NumberOfIntegrationMethods) - .def(py::init(), - py::arg("tensor_adaptor"), py::arg("container"), py::arg("datum"), - py::arg("integration_method"), py::arg("copy") = true) - .def(py::init(), - py::arg("tensor_adaptor"), py::arg("container"), py::arg("datum"), - py::arg("integration_method"), py::arg("copy") = true) - .def(py::init(), - py::arg("tensor_adaptor"), py::arg("container"), py::arg("datum"), - py::arg("integration_method"), py::arg("copy") = true); - py::class_( - tensor_adaptor_sub_module, "ConnectivityIdsTensorAdaptor") - .def(py::init(), - py::arg("container")) - .def(py::init(), - py::arg("container")) - .def(py::init(), - py::arg("container")) - .def(py::init(), - py::arg("tensor_adaptor"), py::arg("copy") = true); + py::class_(tensor_adaptor_sub_module, "ConnectivityIdsTensorAdaptor") + .def(py::init(), + py::arg("container")) + .def(py::init(), + py::arg("container")) + .def(py::init(), + py::arg("container")) + .def(py::init(), + py::arg("tensor_adaptor"), + py::arg("copy") = true); - py::class_( - tensor_adaptor_sub_module, "NodalNeighbourCountTensorAdaptor") - .def(py::init(), - py::arg("tensor_adaptor"), py::arg("entity_container"), py::arg("copy") = true) - .def(py::init(), - py::arg("tensor_adaptor"), py::arg("entity_container"), py::arg("copy") = true) - .def(py::init(), - py::arg("nodes_container"), py::arg("entity_container")) - .def(py::init(), - py::arg("nodes_container"), py::arg("entity_container")); + py::class_(tensor_adaptor_sub_module, "NodalNeighbourCountTensorAdaptor") + .def(py::init(), + py::arg("tensor_adaptor"), + py::arg("entity_container"), + py::arg("copy") = true) + .def(py::init(), + py::arg("tensor_adaptor"), + py::arg("entity_container"), + py::arg("copy") = true) + .def(py::init(), + py::arg("nodes_container"), + py::arg("entity_container")) + .def(py::init(), + py::arg("nodes_container"), + py::arg("entity_container")); + + py::class_ geometric_tensor_adaptor(tensor_adaptor_sub_module, "GeometryMetricsTensorAdaptor"); + + py::enum_(geometric_tensor_adaptor,"DatumType") + .value("DomainSize", GeometryMetricsTensorAdaptor::DatumType::DomainSize) + .export_values(); + + geometric_tensor_adaptor + .def(py::init(), + py::arg("tensor_adaptor"), + py::arg("datum"), + py::arg("copy") = true) + .def(py::init(), + py::arg("container"), + py::arg("datum")) + .def(py::init(), + py::arg("container"), + py::arg("datum")) + .def(py::init(), + py::arg("container"), + py::arg("datum")); } } // namespace Kratos::Python. \ No newline at end of file diff --git a/kratos/tensor_adaptors/geometry_metrics_tensor_adaptor.cpp b/kratos/tensor_adaptors/geometry_metrics_tensor_adaptor.cpp new file mode 100644 index 000000000000..02a5e64d408e --- /dev/null +++ b/kratos/tensor_adaptors/geometry_metrics_tensor_adaptor.cpp @@ -0,0 +1,151 @@ +// | / | +// ' / __| _` | __| _ \ __| +// . \ | ( | | ( |\__ ` +// _|\_\_| \__,_|\__|\___/ ____/ +// Multi-Physics +// +// License: BSD License +// Kratos default license: kratos/license.txt +// +// Main authors: Suneth Warnakulasuriya +// + +// System includes +#include + +// External includes + +// Project includes +#include "utilities/atomic_utilities.h" +#include "utilities/data_type_traits.h" + +// Include base h +#include "geometry_metrics_tensor_adaptor.h" + +namespace Kratos { + +namespace GeometryMetricsTensorAdaptorHelperUtils { + +DenseVector GetShape( + const unsigned int NumberOfEntities, + GeometryMetricsTensorAdaptor::DatumType Datum) +{ + switch (Datum) { + case GeometryMetricsTensorAdaptor::DatumType::DomainSize: + return DenseVector(1, NumberOfEntities); + } + + return DenseVector(0); +} + +template +const ModelPart::GeometryType& GetGeometry(const TEntityType& rEntity) +{ + if constexpr(std::is_same_v) { + return rEntity; + } else { + return rEntity.GetGeometry(); + } +} + +template +void FillDomainSize( + Kratos::span DataSpan, + const TContainerType& rContainer) +{ + IndexPartition(rContainer.size()).for_each([&rContainer, &DataSpan](const auto Index) { + DataSpan[Index] = GetGeometry(*(rContainer.begin() + Index)).DomainSize(); + }); +} + +template +void FillData( + Kratos::span DataSpan, + const GeometryMetricsTensorAdaptor::DatumType Datum, + const TContainerType& rContainer) +{ + switch (Datum) { + case GeometryMetricsTensorAdaptor::DatumType::DomainSize: + FillDomainSize(DataSpan, rContainer); + break; + } +} + +} // namespace GeometryMetricsTensorAdaptorHelperUtils + +template +GeometryMetricsTensorAdaptor::GeometryMetricsTensorAdaptor( + TContainerPointerType pContainer, + const DatumType Datum) + : mDatum(Datum) +{ + this->mpContainer = pContainer; + this->mpStorage = Kratos::make_shared(DenseVector(1, pContainer->size())); +} + +GeometryMetricsTensorAdaptor::GeometryMetricsTensorAdaptor( + const TensorAdaptor& rOther, + const DatumType Datum, + const bool Copy) + : BaseType(rOther, Copy), + mDatum(Datum) +{ + KRATOS_TRY + + if (!HoldsAlternative::Evaluate(this->GetContainer())) { + KRATOS_ERROR << "GeometryMetricsTensorAdaptor can only be used with tensor data " + "having geometry, condition or element containers."; + } + + const auto& current_shape = this->Shape(); + + KRATOS_ERROR_IF(current_shape.size() < 1) << "Tensor data's first dimension should represent number of entities [ tensor adaptor = " << *this << " ].\n"; + + const auto& required_shape = GeometryMetricsTensorAdaptorHelperUtils::GetShape(current_shape[0], Datum); + + for (IndexType i = 0; i < required_shape.size(); ++i) { + KRATOS_ERROR_IF_NOT(current_shape[i] == required_shape[i]) + << "Incompatible tensor data shape [ required tensor data shape = " << required_shape + << ", current tensor data shape = " << current_shape << ", tensor adaptor = " << *this << " ].\n"; + } + + KRATOS_CATCH(""); +} + +void GeometryMetricsTensorAdaptor::CollectData() +{ + KRATOS_TRY + + std::visit([this](auto pContainer) { + using container_type = BareType; + if constexpr(IsInList) { + GeometryMetricsTensorAdaptorHelperUtils::FillData(this->ViewData(), this->mDatum, *pContainer); + } + + }, this->GetContainer()); + + KRATOS_CATCH(""); +} + +void GeometryMetricsTensorAdaptor::StoreData() +{ + KRATOS_ERROR << "StoreData method is not implemented."; +} + +std::string GeometryMetricsTensorAdaptor::Info() const +{ + std::stringstream info; + // info << "GeometryMetricsTensorAdaptor:"; + // std::visit([&info](auto pContainer) { + // info << " number of " << ModelPart::Container>::GetEntityName() << " = " << pContainer->size(); + // }, this->mpEntityContainer); + // info << ", " << BaseType::Info(); + return info.str(); +} + +template KRATOS_API(KRATOS_CORE) GeometryMetricsTensorAdaptor::GeometryMetricsTensorAdaptor(ModelPart::GeometryContainerType::Pointer, GeometryMetricsTensorAdaptor::DatumType); +template KRATOS_API(KRATOS_CORE) GeometryMetricsTensorAdaptor::GeometryMetricsTensorAdaptor(ModelPart::ConditionsContainerType::Pointer, GeometryMetricsTensorAdaptor::DatumType); +template KRATOS_API(KRATOS_CORE) GeometryMetricsTensorAdaptor::GeometryMetricsTensorAdaptor(ModelPart::ElementsContainerType::Pointer, GeometryMetricsTensorAdaptor::DatumType); + +} // namespace Kratos \ No newline at end of file diff --git a/kratos/tensor_adaptors/geometry_metrics_tensor_adaptor.h b/kratos/tensor_adaptors/geometry_metrics_tensor_adaptor.h new file mode 100644 index 000000000000..c263adf77013 --- /dev/null +++ b/kratos/tensor_adaptors/geometry_metrics_tensor_adaptor.h @@ -0,0 +1,119 @@ +// | / | +// ' / __| _` | __| _ \ __| +// . \ | ( | | ( |\__ ` +// _|\_\_| \__,_|\__|\___/ ____/ +// Multi-Physics +// +// License: BSD License +// Kratos default license: kratos/license.txt +// +// Main authors: Suneth Warnakulasuriya +// + +#pragma once + +// System includes +#include + +// External includes + +// Project includes +#include "tensor_adaptors/tensor_adaptor.h" + +namespace Kratos { + +///@name Kratos Classes +///@{ + +/** + * @class GeometryMetricsTensorAdaptor + * @ingroup TensorAdaptors + * @brief Adaptor class for calculating neighbour entities for nodes. + * + * @details This class provides an interface to calculate neighbour entities ( @p pEntityContainer i.e. conditions / elements) for a given specific + * @p pNodes. tensor data associated with Kratos entities' property variables. This @ref TensorAdaptor only implements + * the @ref CollectData method. + * + * @section NodalNeighbourCountTensorAdaptor_supported_container Supported entity container types + * - @ref ModelPart::ConditionsContainerType + * - @ref ModelPart::ElementsContainerType + * + * @section NodalNeighbourCountTensorAdaptor_usage Usage + * - Use @ref Check to verify that the variable exists and they are holding unique memory locations in the entities' properties before collecting/storing data. + * - Use @ref CollectData to fill internal data with the number of neighbouring entities. + * + * @author Suneth Warnakulasuriya + * @see @ref TensorAdaptor Base class. + */ +class KRATOS_API(KRATOS_CORE) GeometryMetricsTensorAdaptor: public TensorAdaptor { +public: + + ///@name Type definitions + ///@{ + + KRATOS_CLASS_POINTER_DEFINITION(GeometryMetricsTensorAdaptor); + + using BaseType = TensorAdaptor; + + ///@} + ///@name Enums + ///@{ + + enum DatumType + { + DomainSize + }; + + ///@} + ///@name Life cycle + ///@{ + + template + GeometryMetricsTensorAdaptor( + TContainerPointerType pContainer, + const DatumType Datum); + + GeometryMetricsTensorAdaptor( + const TensorAdaptor& rOther, + const DatumType Datum, + const bool Copy = true); + + // Destructor + ~GeometryMetricsTensorAdaptor() override = default; + + ///@} + ///@name Public operations + ///@{ + + /** + * @brief Fill the internal data with number of neightour entities of nodes + * @details This will fill the internal data for each node with its available number of entities (i.e. conditions / elements). + * @throws std::runtime_error if there is an entity having a node with id which is not present in the provided @p pNodes when this object is constructed. + */ + void CollectData() override; + + /** + * @brief Does not do anything + * @throws std::runtime_error always. + */ + void StoreData() override; + + ///@} + ///@name Input and output + ///@{ + + std::string Info() const override; + + ///@} + +private: + ///@name Private member variables + ///@{ + + DatumType mDatum; + + ///@} +}; + +/// @} +} // namespace Kratos \ No newline at end of file diff --git a/kratos/tests/test_tensor_adaptors.py b/kratos/tests/test_tensor_adaptors.py index 2d7df880f067..6f864d73dea8 100644 --- a/kratos/tests/test_tensor_adaptors.py +++ b/kratos/tests/test_tensor_adaptors.py @@ -591,6 +591,32 @@ def test_NodalNeighboursTensorAdaptorElement(self): with self.assertRaises(RuntimeError): ta.StoreData() + def testGeometryMetricsTensorAdaptorDomainSizeCondition(self): + ta = Kratos.TensorAdaptors.GeometryMetricsTensorAdaptor(self.model_part.Conditions, Kratos.TensorAdaptors.GeometryMetricsTensorAdaptor.DomainSize) + ta.CollectData() + for i, condition in enumerate(self.model_part.Conditions): + self.assertEqual(ta.data[i], condition.GetGeometry().DomainSize()) + + def testGeometryMetricsTensorAdaptorDomainSizeElement(self): + ta = Kratos.TensorAdaptors.GeometryMetricsTensorAdaptor(self.model_part.Elements, Kratos.TensorAdaptors.GeometryMetricsTensorAdaptor.DomainSize) + ta.CollectData() + for i, element in enumerate(self.model_part.Elements): + self.assertEqual(ta.data[i], element.GetGeometry().DomainSize()) + + def testGeometryMetricsTensorAdaptorDomainSizeCondition_Empty(self): + model = Kratos.Model() + model_part = model.CreateModelPart("test") + ta = Kratos.TensorAdaptors.GeometryMetricsTensorAdaptor(model_part.Conditions, Kratos.TensorAdaptors.GeometryMetricsTensorAdaptor.DomainSize) + ta.CollectData() + self.assertEqual(ta.data.shape, (0,)) + + def testGeometryMetricsTensorAdaptorDomainSizeElement_Empty(self): + model = Kratos.Model() + model_part = model.CreateModelPart("test") + ta = Kratos.TensorAdaptors.GeometryMetricsTensorAdaptor(model_part.Elements, Kratos.TensorAdaptors.GeometryMetricsTensorAdaptor.DomainSize) + ta.CollectData() + self.assertEqual(ta.data.shape, (0,)) + def __TestCopyTensorAdaptor(self, tensor_adaptor_type, value_getter): var_ta_orig = tensor_adaptor_type(self.model_part.Nodes, Kratos.VELOCITY, data_shape=[2]) var_ta_orig.Check() From 947d2a996f638591214752d51a062eba44703562 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Wed, 4 Feb 2026 08:14:44 +0100 Subject: [PATCH 035/116] add more checks --- .../tests/test_optimization_utils.py | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/applications/OptimizationApplication/tests/test_optimization_utils.py b/applications/OptimizationApplication/tests/test_optimization_utils.py index 9dec93cd5817..f5d4596137c5 100644 --- a/applications/OptimizationApplication/tests/test_optimization_utils.py +++ b/applications/OptimizationApplication/tests/test_optimization_utils.py @@ -183,6 +183,9 @@ def test_MapConditionDataToNodalData(self): self.assertVectorAlmostEqual(nodal_ta_v.data.shape, [self.model_part.NumberOfNodes(), 3]) self.assertVectorAlmostEqual(nodal_ta_p.data.shape, [self.model_part.NumberOfNodes()]) + self.assertVectorAlmostEqual(numpy.sum(nodal_ta_v.data, axis=0), numpy.sum(condition_ta_v.data, axis=0)) + self.assertAlmostEqual(numpy.sum(nodal_ta_p.data, axis=0), numpy.sum(condition_ta_p.data, axis=0)) + Kratos.VariableUtils().SetNonHistoricalVariableToZero(Kratos.DENSITY, self.model_part.Nodes) Kratos.VariableUtils().SetNonHistoricalVariableToZero(Kratos.ACCELERATION, self.model_part.Nodes) for entity in self.model_part.Conditions: @@ -199,17 +202,20 @@ def test_MapElementDataToNodalData(self): entity.SetValue(Kratos.VELOCITY, Kratos.Array3([entity.Id, entity.Id + 1, entity.Id + 3])) entity.SetValue(Kratos.PRESSURE, entity.Id + 4) - condition_ta_v = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Elements, Kratos.VELOCITY) - condition_ta_v.CollectData() - condition_ta_p = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Elements, Kratos.PRESSURE) - condition_ta_p.CollectData() + element_ta_v = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Elements, Kratos.VELOCITY) + element_ta_v.CollectData() + element_ta_p = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Elements, Kratos.PRESSURE) + element_ta_p.CollectData() - nodal_ta_v = KratosOA.OptimizationUtils.MapContainerDataToNodalData(condition_ta_v, self.model_part.Nodes) - nodal_ta_p = KratosOA.OptimizationUtils.MapContainerDataToNodalData(condition_ta_p, self.model_part.Nodes) + nodal_ta_v = KratosOA.OptimizationUtils.MapContainerDataToNodalData(element_ta_v, self.model_part.Nodes) + nodal_ta_p = KratosOA.OptimizationUtils.MapContainerDataToNodalData(element_ta_p, self.model_part.Nodes) self.assertVectorAlmostEqual(nodal_ta_v.data.shape, [self.model_part.NumberOfNodes(), 3]) self.assertVectorAlmostEqual(nodal_ta_p.data.shape, [self.model_part.NumberOfNodes()]) + self.assertVectorAlmostEqual(numpy.sum(nodal_ta_v.data, axis=0), numpy.sum(element_ta_v.data, axis=0)) + self.assertAlmostEqual(numpy.sum(nodal_ta_p.data, axis=0), numpy.sum(element_ta_p.data, axis=0)) + Kratos.VariableUtils().SetNonHistoricalVariableToZero(Kratos.DENSITY, self.model_part.Nodes) Kratos.VariableUtils().SetNonHistoricalVariableToZero(Kratos.ACCELERATION, self.model_part.Nodes) for entity in self.model_part.Elements: @@ -242,6 +248,9 @@ def test_MapNodalDataToConditionData(self): self.assertVectorAlmostEqual(entity_ta_v.data.shape, [self.model_part.NumberOfConditions(), 3]) self.assertVectorAlmostEqual(entity_ta_p.data.shape, [self.model_part.NumberOfConditions()]) + self.assertVectorAlmostEqual(numpy.sum(nodal_ta_v.data, axis=0), numpy.sum(entity_ta_v.data, axis=0)) + self.assertAlmostEqual(numpy.sum(nodal_ta_p.data, axis=0), numpy.sum(entity_ta_p.data, axis=0)) + Kratos.VariableUtils().SetNonHistoricalVariableToZero(Kratos.DENSITY, self.model_part.Conditions) Kratos.VariableUtils().SetNonHistoricalVariableToZero(Kratos.ACCELERATION, self.model_part.Conditions) for entity in self.model_part.Conditions: @@ -274,6 +283,9 @@ def test_MapNodalDataToElementData(self): self.assertVectorAlmostEqual(entity_ta_v.data.shape, [self.model_part.NumberOfElements(), 3]) self.assertVectorAlmostEqual(entity_ta_p.data.shape, [self.model_part.NumberOfElements()]) + self.assertVectorAlmostEqual(numpy.sum(nodal_ta_v.data, axis=0), numpy.sum(entity_ta_v.data, axis=0)) + self.assertAlmostEqual(numpy.sum(nodal_ta_p.data, axis=0), numpy.sum(entity_ta_p.data, axis=0)) + Kratos.VariableUtils().SetNonHistoricalVariableToZero(Kratos.DENSITY, self.model_part.Elements) Kratos.VariableUtils().SetNonHistoricalVariableToZero(Kratos.ACCELERATION, self.model_part.Elements) for entity in self.model_part.Elements: From 13d677bbf5ecf8e416ec5a5f8e1946779055db31 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Wed, 4 Feb 2026 13:36:32 +0100 Subject: [PATCH 036/116] fix for the explicit filter tests --- .../explicit_filter_reference_constant.vtu | 2 +- .../filtering/explicit_filter_reference_cosine.vtu | 2 +- .../explicit_filter_reference_gaussian.vtu | 2 +- .../filtering/explicit_filter_reference_linear.vtu | 2 +- .../explicit_filter_reference_quartic.vtu | 2 +- .../explicit_filter_reference_sigmoidal.vtu | 2 +- ...licit_filter_reference_sigmoidal_cloud_mesh.vtu | 2 +- .../tests/filtering/explicit_filters_tests.py | 14 +------------- 8 files changed, 8 insertions(+), 20 deletions(-) diff --git a/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_constant.vtu b/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_constant.vtu index 5526d402466d..a86b2420840e 100644 --- a/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_constant.vtu +++ b/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_constant.vtu @@ -3,7 +3,7 @@ - -5.000000e-01 -5.000000e-01 0.000000e+00 -2.961943e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 -3.070824e-01 6.389248e-02 -2.710893e-01 -3.679346e-01 3.282041e-02 -3.220885e-01 -2.138442e-01 1.579471e-01 -8.425341e-02 -5.000000e-01 0.000000e+00 -5.000000e-01 -1.190794e-01 2.327001e-01 -1.427550e-01 -2.036670e-01 1.587254e-01 -3.367918e-02 -3.646036e-01 3.474723e-02 -2.936288e-01 -6.024280e-02 2.280798e-01 1.199989e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 8.559378e-02 2.458009e-01 6.632135e-02 -1.960239e-01 1.456686e-01 -4.158755e-02 -2.942211e-02 2.123580e-01 1.706852e-01 -3.570974e-01 3.202384e-02 -2.020774e-01 1.419972e-01 2.249515e-01 -5.000000e-01 2.543348e-01 2.298799e-01 -3.399030e-01 2.638923e-01 2.365963e-01 3.246785e-01 -5.000000e-01 0.000000e+00 1.635995e-01 -2.113480e-02 1.653995e-01 2.698530e-01 -1.855443e-01 9.146799e-02 4.150088e-02 1.567550e-01 2.058167e-01 -1.967980e-01 3.018647e-01 2.251813e-01 3.746200e-01 -3.486372e-01 2.585984e-02 -7.966175e-02 2.828160e-01 2.187265e-01 -5.000000e-01 3.894313e-01 2.361269e-01 -3.976151e-01 4.025910e-01 2.376766e-01 -2.415572e-01 4.029806e-01 2.317340e-01 2.708605e-02 3.057637e-01 2.088328e-01 3.573303e-01 -1.642538e-02 5.068238e-02 -1.346532e-01 4.030807e-01 2.220682e-01 2.805837e-01 1.373809e-01 9.572561e-02 1.280589e-01 2.840759e-01 1.710313e-01 5.248984e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 5.000000e-01 2.193098e-01 -3.989868e-01 5.000000e-01 2.036441e-01 -2.625817e-02 4.034426e-01 1.957128e-01 -2.946243e-01 5.000000e-01 2.051985e-01 5.304011e-01 -3.026241e-01 0.000000e+00 -1.890200e-01 5.000000e-01 1.893594e-01 7.468893e-02 4.034414e-01 1.893747e-01 2.479810e-01 2.994380e-01 1.113288e-01 -8.481192e-02 5.000000e-01 1.850986e-01 5.331493e-01 -1.061236e-01 0.000000e+00 1.774451e-01 4.034666e-01 1.497197e-01 2.198726e-02 5.000000e-01 1.813930e-01 3.747089e-01 2.677468e-01 3.136313e-02 1.234675e-01 5.000000e-01 1.593729e-01 5.329600e-01 9.622950e-02 0.000000e+00 2.781282e-01 4.038703e-01 6.797017e-02 2.232866e-01 5.000000e-01 8.535446e-02 5.311495e-01 2.585477e-01 0.000000e+00 4.283062e-01 4.033266e-01 1.274614e-02 3.254498e-01 5.000000e-01 4.389874e-02 5.281597e-01 3.905607e-01 0.000000e+00 4.245887e-01 5.000000e-01 9.045338e-03 5.264592e-01 5.000000e-01 0.000000e+00 + -5.000000e-01 -5.000000e-01 0.000000e+00 -2.954690e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 -3.076218e-01 6.730670e-02 -2.698146e-01 -3.684091e-01 3.682268e-02 -3.210687e-01 -2.152692e-01 1.696515e-01 -8.165576e-02 -5.000000e-01 0.000000e+00 -5.000000e-01 -1.201263e-01 2.427572e-01 -1.393353e-01 -2.057058e-01 1.764073e-01 -2.991886e-02 -3.652212e-01 4.020307e-02 -2.923024e-01 -6.213435e-02 2.469612e-01 1.230270e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 8.486384e-02 2.546585e-01 7.102194e-02 -1.981571e-01 1.665123e-01 -3.725551e-02 -3.157286e-02 2.356577e-01 1.753316e-01 -3.578146e-01 3.830592e-02 -1.995909e-01 1.408093e-01 2.447731e-01 -5.000000e-01 2.542415e-01 2.301170e-01 -3.392484e-01 2.635720e-01 2.484821e-01 3.289313e-01 -5.000000e-01 0.000000e+00 1.686987e-01 -2.344447e-02 1.899916e-01 2.752834e-01 -1.876647e-01 1.105251e-01 4.651544e-02 1.553755e-01 2.299026e-01 -1.946200e-01 3.014690e-01 2.421528e-01 3.789940e-01 -3.494305e-01 3.224430e-02 -7.595017e-02 2.822785e-01 2.385466e-01 -5.000000e-01 3.894072e-01 2.360903e-01 -3.974708e-01 4.025171e-01 2.427420e-01 -2.400169e-01 4.028732e-01 2.438698e-01 3.160794e-02 3.053247e-01 2.304882e-01 3.629834e-01 -1.880867e-02 6.147739e-02 -1.319979e-01 4.029774e-01 2.357441e-01 2.863519e-01 1.357811e-01 1.110552e-01 1.332429e-01 2.834209e-01 1.937152e-01 5.281389e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 5.000000e-01 2.152277e-01 -3.988510e-01 5.000000e-01 2.008792e-01 -2.211396e-02 4.033233e-01 2.138188e-01 -2.937882e-01 5.000000e-01 2.101694e-01 5.357141e-01 -3.036836e-01 0.000000e+00 -1.873007e-01 5.000000e-01 1.956806e-01 7.894423e-02 4.033102e-01 2.088962e-01 2.533139e-01 2.989023e-01 1.271129e-01 -8.245013e-02 5.000000e-01 1.928728e-01 5.387344e-01 -1.085301e-01 0.000000e+00 1.823984e-01 4.033293e-01 1.680583e-01 2.526017e-02 5.000000e-01 1.922700e-01 3.801274e-01 2.670541e-01 3.722506e-02 1.270189e-01 5.000000e-01 1.712776e-01 5.382499e-01 9.470425e-02 0.000000e+00 2.828839e-01 4.037465e-01 7.916664e-02 2.266649e-01 5.000000e-01 9.571167e-02 5.364034e-01 2.580094e-01 0.000000e+00 4.331546e-01 4.032447e-01 1.492143e-02 3.292619e-01 5.000000e-01 4.987022e-02 5.324171e-01 3.904917e-01 0.000000e+00 4.279950e-01 5.000000e-01 1.038714e-02 5.300883e-01 5.000000e-01 0.000000e+00 diff --git a/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_cosine.vtu b/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_cosine.vtu index 82c426d33385..83716bed3169 100644 --- a/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_cosine.vtu +++ b/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_cosine.vtu @@ -3,7 +3,7 @@ - -5.000000e-01 -5.000000e-01 0.000000e+00 -2.986428e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 -3.126588e-01 5.690273e-02 -2.740004e-01 -3.709777e-01 2.814741e-02 -3.235984e-01 -2.299634e-01 1.576581e-01 -9.107717e-02 -5.000000e-01 0.000000e+00 -5.000000e-01 -1.370296e-01 2.373696e-01 -1.435753e-01 -2.208903e-01 1.715295e-01 -3.580827e-02 -3.672690e-01 2.996609e-02 -2.943958e-01 -8.267981e-02 3.110548e-01 1.186403e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 7.931570e-02 3.024453e-01 7.580028e-02 -2.062677e-01 1.468885e-01 -2.970195e-02 -4.438420e-02 2.954877e-01 1.751975e-01 -3.582292e-01 2.658427e-02 -2.017395e-01 1.381018e-01 3.175856e-01 -5.000000e-01 2.567423e-01 2.652866e-01 -3.407705e-01 2.667497e-01 2.792566e-01 3.227029e-01 -5.000000e-01 0.000000e+00 1.862664e-01 -2.652136e-02 1.903250e-01 2.836342e-01 -1.896685e-01 8.609772e-02 5.541016e-02 1.574743e-01 2.524727e-01 -1.986994e-01 3.042998e-01 2.591299e-01 3.783532e-01 -3.491957e-01 2.125955e-02 -7.670522e-02 2.858632e-01 2.465129e-01 -5.000000e-01 3.908385e-01 2.144653e-01 -3.983704e-01 4.036737e-01 2.199241e-01 -2.437576e-01 4.043883e-01 2.185153e-01 3.297034e-02 3.083327e-01 2.070876e-01 3.765880e-01 -1.675971e-02 4.793857e-02 -1.363546e-01 4.043986e-01 2.060763e-01 2.997327e-01 1.408317e-01 8.269695e-02 1.376671e-01 2.867851e-01 1.663110e-01 5.209407e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 5.000000e-01 1.725070e-01 -3.994850e-01 5.000000e-01 1.820697e-01 -2.838751e-02 4.044001e-01 1.840740e-01 -2.973324e-01 5.000000e-01 1.820962e-01 5.320424e-01 -3.023223e-01 0.000000e+00 -1.925594e-01 5.000000e-01 1.744842e-01 7.733417e-02 4.044313e-01 1.519615e-01 2.581385e-01 3.021680e-01 8.378927e-02 -8.605587e-02 5.000000e-01 1.571643e-01 5.429914e-01 -1.047899e-01 0.000000e+00 1.809326e-01 4.044644e-01 1.021295e-01 1.932354e-02 5.000000e-01 1.325676e-01 3.840030e-01 2.700755e-01 2.459401e-02 1.231926e-01 5.000000e-01 1.009373e-01 5.441747e-01 9.913723e-02 0.000000e+00 2.821560e-01 4.044607e-01 5.337488e-02 2.253708e-01 5.000000e-01 6.189307e-02 5.368486e-01 2.606025e-01 0.000000e+00 4.297449e-01 4.037568e-01 7.614262e-03 3.256778e-01 5.000000e-01 2.672517e-02 5.290418e-01 3.909747e-01 0.000000e+00 4.247725e-01 5.000000e-01 6.106036e-03 5.223648e-01 5.000000e-01 0.000000e+00 + -5.000000e-01 -5.000000e-01 0.000000e+00 -2.991491e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 -3.100072e-01 4.989820e-02 -2.748267e-01 -3.702636e-01 2.693719e-02 -3.245682e-01 -2.254517e-01 1.489256e-01 -9.196332e-02 -5.000000e-01 0.000000e+00 -5.000000e-01 -1.280630e-01 2.070997e-01 -1.450095e-01 -2.189538e-01 1.749638e-01 -3.659211e-02 -3.673344e-01 3.140215e-02 -2.954990e-01 -7.607154e-02 2.981890e-01 1.182097e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 8.582400e-02 2.638892e-01 7.642142e-02 -2.072924e-01 1.605990e-01 -3.029159e-02 -4.244769e-02 3.105166e-01 1.752558e-01 -3.587013e-01 2.914530e-02 -2.034831e-01 1.411768e-01 3.098708e-01 -5.000000e-01 2.584408e-01 2.268754e-01 -3.414377e-01 2.681899e-01 2.538098e-01 3.217517e-01 -5.000000e-01 0.000000e+00 1.881924e-01 -2.704537e-02 2.105209e-01 2.847983e-01 -1.909550e-01 9.555792e-02 5.526918e-02 1.585090e-01 2.659499e-01 -2.004494e-01 3.050502e-01 2.462800e-01 3.777562e-01 -3.496018e-01 2.333182e-02 -7.851439e-02 2.866093e-01 2.448954e-01 -5.000000e-01 3.910091e-01 1.775422e-01 -3.986135e-01 4.038014e-01 1.891308e-01 -2.450655e-01 4.045503e-01 1.991841e-01 3.197844e-02 3.088370e-01 2.109643e-01 3.780917e-01 -1.709096e-02 5.252044e-02 -1.382457e-01 4.045633e-01 1.948586e-01 3.012772e-01 1.413521e-01 8.940033e-02 1.376671e-01 2.873000e-01 1.737178e-01 5.190268e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 5.000000e-01 1.375057e-01 -3.996857e-01 5.000000e-01 1.516662e-01 -3.014878e-02 4.045626e-01 1.797287e-01 -2.981346e-01 5.000000e-01 1.575114e-01 5.305128e-01 -3.026884e-01 0.000000e+00 -1.940829e-01 5.000000e-01 1.568791e-01 7.628034e-02 4.045778e-01 1.523165e-01 2.585399e-01 3.025401e-01 8.752896e-02 -8.793837e-02 5.000000e-01 1.464772e-01 5.424553e-01 -1.051667e-01 0.000000e+00 1.804156e-01 4.045889e-01 1.034956e-01 1.770496e-02 5.000000e-01 1.274626e-01 3.844219e-01 2.704743e-01 2.568950e-02 1.220064e-01 5.000000e-01 9.875492e-02 5.442603e-01 9.954487e-02 0.000000e+00 2.818124e-01 4.045666e-01 5.408987e-02 2.244435e-01 5.000000e-01 6.085503e-02 5.366422e-01 2.609213e-01 0.000000e+00 4.292998e-01 4.038212e-01 7.655538e-03 3.248422e-01 5.000000e-01 2.617334e-02 5.283949e-01 3.910444e-01 0.000000e+00 4.238597e-01 5.000000e-01 5.957351e-03 5.212440e-01 5.000000e-01 0.000000e+00 diff --git a/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_gaussian.vtu b/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_gaussian.vtu index 00688f47f725..acd7ad179240 100644 --- a/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_gaussian.vtu +++ b/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_gaussian.vtu @@ -3,7 +3,7 @@ - -5.000000e-01 -5.000000e-01 0.000000e+00 -3.001312e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 -3.152543e-01 4.293939e-02 -2.772293e-01 -3.700674e-01 1.495014e-02 -3.270142e-01 -2.616718e-01 1.296386e-01 -9.921406e-02 -5.000000e-01 0.000000e+00 -5.000000e-01 -2.353148e-01 2.728018e-01 -1.523599e-01 -2.714055e-01 1.565633e-01 -4.898744e-02 -3.663462e-01 1.543523e-02 -3.015572e-01 -1.981923e-01 4.600410e-01 1.038833e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 1.400560e-01 4.767370e-01 8.808214e-02 -2.563362e-01 1.766803e-01 1.569528e-02 -1.093621e-01 4.657042e-01 1.628646e-01 -3.586624e-01 1.837332e-02 -2.015222e-01 2.242279e-01 4.371228e-01 -5.000000e-01 2.718792e-01 2.311522e-01 -3.420668e-01 2.885887e-01 2.861582e-01 3.103887e-01 -5.000000e-01 0.000000e+00 2.827267e-01 -3.447501e-02 2.872851e-01 3.244449e-01 -2.096290e-01 1.227449e-01 1.070332e-01 2.207053e-01 3.388645e-01 -2.023288e-01 3.146565e-01 2.156900e-01 3.822891e-01 -3.491919e-01 1.849880e-02 -8.081249e-02 2.969653e-01 1.938334e-01 -5.000000e-01 3.922312e-01 1.922180e-01 -3.987699e-01 4.052031e-01 2.375814e-01 -2.455221e-01 4.056020e-01 1.769426e-01 3.393677e-02 3.161114e-01 1.754478e-01 4.231251e-01 -3.290935e-04 3.980504e-02 -1.410245e-01 4.054433e-01 1.492209e-01 3.489923e-01 1.662057e-01 7.507330e-02 1.423558e-01 2.954196e-01 1.534443e-01 5.110105e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 5.000000e-01 1.390756e-01 -3.997629e-01 5.000000e-01 1.769014e-01 -3.611602e-02 4.053532e-01 1.359002e-01 -2.980309e-01 5.000000e-01 1.495778e-01 5.254188e-01 -3.011991e-01 0.000000e+00 -1.949478e-01 5.000000e-01 1.240157e-01 7.082913e-02 4.051843e-01 1.225193e-01 2.614016e-01 3.057631e-01 6.295961e-02 -9.225646e-02 5.000000e-01 1.097848e-01 5.695029e-01 -1.032512e-01 0.000000e+00 1.757996e-01 4.049106e-01 8.522191e-02 1.125653e-02 5.000000e-01 1.008698e-01 3.908313e-01 2.751824e-01 1.633525e-02 1.160317e-01 5.000000e-01 8.206242e-02 5.479816e-01 1.065723e-01 0.000000e+00 2.759902e-01 4.046806e-01 3.983771e-02 2.186237e-01 5.000000e-01 4.823144e-02 5.230635e-01 2.622549e-01 0.000000e+00 4.181602e-01 4.038192e-01 3.717766e-03 3.166557e-01 5.000000e-01 1.747905e-02 5.130549e-01 3.909732e-01 0.000000e+00 4.125688e-01 5.000000e-01 2.691875e-03 5.082515e-01 5.000000e-01 0.000000e+00 + -5.000000e-01 -5.000000e-01 0.000000e+00 -3.007196e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 -3.065034e-01 2.461872e-02 -2.788266e-01 -3.689216e-01 1.477026e-02 -3.298575e-01 -2.442489e-01 1.116619e-01 -9.965241e-02 -5.000000e-01 0.000000e+00 -5.000000e-01 -1.489714e-01 1.421952e-01 -1.600906e-01 -2.630415e-01 1.498938e-01 -5.029431e-02 -3.658966e-01 1.499640e-02 -3.247315e-01 -1.807785e-01 4.150662e-01 1.036977e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 1.166647e-01 2.882023e-01 8.467524e-02 -2.516502e-01 1.692512e-01 6.828922e-03 -1.266132e-01 4.580222e-01 1.619512e-01 -3.583053e-01 1.769232e-02 -2.279133e-01 2.380321e-01 4.755744e-01 -5.000000e-01 2.668125e-01 1.566494e-01 -3.445339e-01 2.865280e-01 2.415987e-01 3.082706e-01 -5.000000e-01 0.000000e+00 2.803267e-01 -4.437674e-02 2.656870e-01 3.169091e-01 -2.064629e-01 1.133210e-01 1.261006e-01 2.368107e-01 3.728273e-01 -2.077050e-01 3.145934e-01 1.896257e-01 3.753464e-01 -3.488286e-01 1.742187e-02 -8.583488e-02 2.983067e-01 1.794044e-01 -5.000000e-01 3.916102e-01 1.205986e-01 -3.991628e-01 4.047192e-01 1.628128e-01 -2.484632e-01 4.056065e-01 1.377838e-01 3.023691e-02 3.167875e-01 1.609727e-01 4.056037e-01 -3.865631e-03 3.480217e-02 -1.449796e-01 4.056228e-01 1.213960e-01 3.547500e-01 1.669525e-01 7.360623e-02 1.396955e-01 2.960251e-01 1.419123e-01 5.054796e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 5.000000e-01 8.278275e-02 -4.000050e-01 5.000000e-01 1.129721e-01 -4.006627e-02 4.055402e-01 1.117794e-01 -2.994376e-01 5.000000e-01 1.028399e-01 5.163163e-01 -3.009242e-01 0.000000e+00 -1.978510e-01 5.000000e-01 9.015215e-02 6.645628e-02 4.052832e-01 1.001378e-01 2.581368e-01 3.060237e-01 5.668889e-02 -9.568121e-02 5.000000e-01 8.112439e-02 5.436701e-01 -1.012313e-01 0.000000e+00 1.700746e-01 4.049768e-01 6.912835e-02 7.405549e-03 5.000000e-01 7.448219e-02 3.901223e-01 2.754510e-01 1.539805e-02 1.109649e-01 5.000000e-01 6.066822e-02 5.339067e-01 1.044745e-01 0.000000e+00 2.696705e-01 4.047104e-01 3.218763e-02 2.124861e-01 5.000000e-01 3.583752e-02 5.186325e-01 2.620677e-01 0.000000e+00 4.134807e-01 4.038251e-01 3.069018e-03 3.109666e-01 5.000000e-01 1.302683e-02 5.094036e-01 3.909688e-01 0.000000e+00 4.082488e-01 5.000000e-01 2.035539e-03 5.052721e-01 5.000000e-01 0.000000e+00 diff --git a/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_linear.vtu b/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_linear.vtu index 419879a29f0b..2b861cbba03f 100644 --- a/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_linear.vtu +++ b/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_linear.vtu @@ -3,7 +3,7 @@ - -5.000000e-01 -5.000000e-01 0.000000e+00 -2.981906e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 -3.104114e-01 5.833304e-02 -2.733140e-01 -3.698375e-01 2.895156e-02 -3.232342e-01 -2.225590e-01 1.536248e-01 -9.010542e-02 -5.000000e-01 0.000000e+00 -5.000000e-01 -1.278121e-01 2.264712e-01 -1.438137e-01 -2.133061e-01 1.644571e-01 -3.544692e-02 -3.662447e-01 3.104836e-02 -2.944183e-01 -7.294457e-02 2.818546e-01 1.182315e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 8.237290e-02 2.758439e-01 7.104819e-02 -2.020373e-01 1.442379e-01 -3.502321e-02 -3.785397e-02 2.644501e-01 1.727875e-01 -3.577401e-01 2.733918e-02 -2.029992e-01 1.388620e-01 2.877111e-01 -5.000000e-01 2.554177e-01 2.510282e-01 -3.405830e-01 2.653979e-01 2.616592e-01 3.218611e-01 -5.000000e-01 0.000000e+00 1.761533e-01 -2.414649e-02 1.783535e-01 2.775998e-01 -1.880238e-01 8.546791e-02 4.904573e-02 1.566027e-01 2.365826e-01 -1.993585e-01 3.030316e-01 2.446753e-01 3.759507e-01 -3.489716e-01 2.195991e-02 -7.875274e-02 2.845821e-01 2.329121e-01 -5.000000e-01 3.904222e-01 2.130617e-01 -3.983014e-01 4.033059e-01 2.157784e-01 -2.434837e-01 4.038989e-01 2.144162e-01 2.968586e-02 3.074049e-01 2.026214e-01 3.682031e-01 -1.660181e-02 4.805745e-02 -1.369069e-01 4.039758e-01 2.023529e-01 2.920619e-01 1.396837e-01 8.221233e-02 1.323116e-01 2.857868e-01 1.658515e-01 5.214201e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 5.000000e-01 1.763436e-01 -3.993813e-01 5.000000e-01 1.850483e-01 -2.895866e-02 4.040253e-01 1.856884e-01 -2.968855e-01 5.000000e-01 1.844075e-01 5.296627e-01 -3.022416e-01 0.000000e+00 -1.918277e-01 5.000000e-01 1.783451e-01 7.539537e-02 4.040854e-01 1.616903e-01 2.531487e-01 3.013970e-01 8.598960e-02 -8.632715e-02 5.000000e-01 1.663346e-01 5.386964e-01 -1.049146e-01 0.000000e+00 1.783922e-01 4.042120e-01 1.081264e-01 1.924490e-02 5.000000e-01 1.463554e-01 3.798623e-01 2.693194e-01 2.572180e-02 1.227687e-01 5.000000e-01 1.080888e-01 5.393072e-01 9.802253e-02 0.000000e+00 2.800085e-01 4.042698e-01 5.629668e-02 2.246634e-01 5.000000e-01 6.780308e-02 5.339478e-01 2.600282e-01 0.000000e+00 4.283178e-01 4.036565e-01 8.347929e-03 3.252731e-01 5.000000e-01 3.002150e-02 5.288320e-01 3.908640e-01 0.000000e+00 4.249093e-01 5.000000e-01 6.772468e-03 5.237764e-01 5.000000e-01 0.000000e+00 + -5.000000e-01 -5.000000e-01 0.000000e+00 -2.984309e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 -3.090632e-01 5.436174e-02 -2.735886e-01 -3.696047e-01 2.910589e-02 -3.235740e-01 -2.208024e-01 1.524587e-01 -9.004908e-02 -5.000000e-01 0.000000e+00 -5.000000e-01 -1.234879e-01 2.117089e-01 -1.434763e-01 -2.131620e-01 1.735417e-01 -3.474472e-02 -3.665349e-01 3.364957e-02 -2.946188e-01 -7.011321e-02 2.808892e-01 1.189132e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 8.611614e-02 2.541727e-01 7.332653e-02 -2.034018e-01 1.608959e-01 -3.334529e-02 -3.762377e-02 2.831589e-01 1.743563e-01 -3.582901e-01 3.103324e-02 -2.032132e-01 1.405015e-01 2.886430e-01 -5.000000e-01 2.568230e-01 2.274291e-01 -3.408521e-01 2.664978e-01 2.487852e-01 3.224208e-01 -5.000000e-01 0.000000e+00 1.795062e-01 -2.522745e-02 2.007827e-01 2.804995e-01 -1.896018e-01 9.840379e-02 5.094643e-02 1.569336e-01 2.532075e-01 -1.998390e-01 3.036144e-01 2.402862e-01 3.772478e-01 -3.494974e-01 2.529894e-02 -7.853827e-02 2.850798e-01 2.369196e-01 -5.000000e-01 3.906297e-01 1.896381e-01 -3.984449e-01 4.034598e-01 1.961450e-01 -2.440077e-01 4.040684e-01 2.045413e-01 3.064587e-02 3.076936e-01 2.110629e-01 3.714932e-01 -1.752072e-02 5.460841e-02 -1.374321e-01 4.041132e-01 1.985617e-01 2.953276e-01 1.396039e-01 9.188527e-02 1.340248e-01 2.860416e-01 1.773893e-01 5.212856e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 5.000000e-01 1.529200e-01 -3.995081e-01 5.000000e-01 1.656706e-01 -2.887148e-02 4.041420e-01 1.876080e-01 -2.973288e-01 5.000000e-01 1.699102e-01 5.303911e-01 -3.027443e-01 0.000000e+00 -1.924497e-01 5.000000e-01 1.696402e-01 7.610231e-02 4.041857e-01 1.671537e-01 2.552363e-01 3.015882e-01 9.319230e-02 -8.691318e-02 5.000000e-01 1.617716e-01 5.406742e-01 -1.056860e-01 0.000000e+00 1.795923e-01 4.042944e-01 1.140288e-01 1.917062e-02 5.000000e-01 1.462019e-01 3.820607e-01 2.695205e-01 2.801299e-02 1.232378e-01 5.000000e-01 1.109758e-01 5.415876e-01 9.798155e-02 0.000000e+00 2.813950e-01 4.043421e-01 5.985903e-02 2.253657e-01 5.000000e-01 7.030418e-02 5.355878e-01 2.602398e-01 0.000000e+00 4.295031e-01 4.037088e-01 8.804585e-03 3.260202e-01 5.000000e-01 3.112911e-02 5.299791e-01 3.909227e-01 0.000000e+00 4.256232e-01 5.000000e-01 7.006080e-03 5.243080e-01 5.000000e-01 0.000000e+00 diff --git a/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_quartic.vtu b/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_quartic.vtu index 3a67964db7ce..8da26cf239a8 100644 --- a/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_quartic.vtu +++ b/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_quartic.vtu @@ -3,7 +3,7 @@ - -5.000000e-01 -5.000000e-01 0.000000e+00 -2.998969e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 -3.170770e-01 4.526861e-02 -2.765871e-01 -3.723399e-01 2.032323e-02 -3.264382e-01 -2.629246e-01 1.498138e-01 -9.687133e-02 -5.000000e-01 0.000000e+00 -5.000000e-01 -2.024218e-01 2.665885e-01 -1.454571e-01 -2.632818e-01 1.732147e-01 -4.268763e-02 -3.685444e-01 2.109010e-02 -2.990922e-01 -1.823967e-01 4.527892e-01 1.090457e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 1.076890e-01 4.389637e-01 9.389333e-02 -2.398753e-01 1.771325e-01 1.460363e-02 -9.556264e-02 4.235721e-01 1.725859e-01 -3.597339e-01 2.318767e-02 -1.981396e-01 1.923906e-01 4.511643e-01 -5.000000e-01 2.698989e-01 2.686649e-01 -3.414545e-01 2.863292e-01 3.242353e-01 3.161824e-01 -5.000000e-01 0.000000e+00 2.509375e-01 -3.909176e-02 2.655015e-01 3.179229e-01 -2.037063e-01 1.150333e-01 1.024190e-01 1.919045e-01 3.402446e-01 -1.995363e-01 3.144486e-01 2.522899e-01 3.854733e-01 -3.496947e-01 2.037917e-02 -7.166734e-02 2.973139e-01 2.379658e-01 -5.000000e-01 3.923791e-01 2.031557e-01 -3.986430e-01 4.052595e-01 2.412018e-01 -2.449849e-01 4.060003e-01 2.034545e-01 4.069292e-02 3.151376e-01 1.942993e-01 4.159345e-01 -1.061202e-02 4.523956e-02 -1.378877e-01 4.057685e-01 1.738266e-01 3.466461e-01 1.569173e-01 8.728008e-02 1.506505e-01 2.940939e-01 1.677283e-01 5.152898e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 5.000000e-01 1.561236e-01 -3.996853e-01 5.000000e-01 1.765673e-01 -2.897155e-02 4.055957e-01 1.536036e-01 -2.979861e-01 5.000000e-01 1.636750e-01 5.333827e-01 -3.021069e-01 0.000000e+00 -1.941093e-01 5.000000e-01 1.424123e-01 7.744282e-02 4.054143e-01 1.340017e-01 2.673262e-01 3.056419e-01 7.411872e-02 -8.853363e-02 5.000000e-01 1.234203e-01 5.649236e-01 -1.037354e-01 0.000000e+00 1.810569e-01 4.051220e-01 9.133138e-02 1.668933e-02 5.000000e-01 1.101165e-01 3.952287e-01 2.740325e-01 1.965099e-02 1.202359e-01 5.000000e-01 8.731429e-02 5.555420e-01 1.051342e-01 0.000000e+00 2.819087e-01 4.048794e-01 4.446207e-02 2.219188e-01 5.000000e-01 5.125733e-02 5.347124e-01 2.626411e-01 0.000000e+00 4.257231e-01 4.039379e-01 5.080466e-03 3.210857e-01 5.000000e-01 2.022816e-02 5.216467e-01 3.911405e-01 0.000000e+00 4.184422e-01 5.000000e-01 3.895843e-03 5.142252e-01 5.000000e-01 0.000000e+00 + -5.000000e-01 -5.000000e-01 0.000000e+00 -3.005306e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 -3.084094e-01 2.904672e-02 -2.781905e-01 -3.702707e-01 1.833036e-02 -3.288798e-01 -2.421803e-01 1.241736e-01 -9.836984e-02 -5.000000e-01 0.000000e+00 -5.000000e-01 -1.429232e-01 1.650544e-01 -1.544300e-01 -2.507383e-01 1.620965e-01 -4.596288e-02 -3.675337e-01 2.014390e-02 -3.092238e-01 -1.458249e-01 3.865500e-01 1.075637e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 1.018206e-01 2.788063e-01 8.602138e-02 -2.347391e-01 1.686538e-01 -5.404185e-03 -9.085495e-02 4.052340e-01 1.690779e-01 -3.591343e-01 2.200021e-02 -2.150380e-01 1.934152e-01 4.413785e-01 -5.000000e-01 2.657863e-01 1.816259e-01 -3.437672e-01 2.829912e-01 2.618104e-01 3.122586e-01 -5.000000e-01 0.000000e+00 2.408036e-01 -3.830894e-02 2.496639e-01 3.070750e-01 -2.011873e-01 1.061233e-01 9.931205e-02 1.965532e-01 3.447156e-01 -2.058705e-01 3.138169e-01 2.185863e-01 3.765714e-01 -3.492675e-01 1.899713e-02 -7.959867e-02 2.976614e-01 2.183210e-01 -5.000000e-01 3.918160e-01 1.355591e-01 -3.990732e-01 4.047109e-01 1.676189e-01 -2.482452e-01 4.057764e-01 1.578931e-01 3.474571e-02 3.155027e-01 1.779249e-01 3.998883e-01 -1.102375e-02 4.102022e-02 -1.431426e-01 4.057045e-01 1.417348e-01 3.405905e-01 1.571028e-01 8.358277e-02 1.450037e-01 2.944865e-01 1.543616e-01 5.092707e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 5.000000e-01 9.948997e-02 -3.999737e-01 5.000000e-01 1.186840e-01 -3.492869e-02 4.056015e-01 1.284975e-01 -2.993998e-01 5.000000e-01 1.157468e-01 5.226269e-01 -3.017300e-01 0.000000e+00 -1.972658e-01 5.000000e-01 1.062603e-01 7.149767e-02 4.054296e-01 1.126431e-01 2.611577e-01 3.057186e-01 6.658259e-02 -9.307051e-02 5.000000e-01 9.522405e-02 5.432768e-01 -1.025692e-01 0.000000e+00 1.746756e-01 4.051303e-01 7.618045e-02 1.156304e-02 5.000000e-01 8.617040e-02 3.885158e-01 2.739824e-01 1.803284e-02 1.146618e-01 5.000000e-01 6.831860e-02 5.409475e-01 1.042419e-01 0.000000e+00 2.752519e-01 4.048810e-01 3.694911e-02 2.159970e-01 5.000000e-01 4.004667e-02 5.274488e-01 2.624167e-01 0.000000e+00 4.196299e-01 4.039275e-01 4.256082e-03 3.153229e-01 5.000000e-01 1.584339e-02 5.163838e-01 3.911172e-01 0.000000e+00 4.132905e-01 5.000000e-01 3.086396e-03 5.099653e-01 5.000000e-01 0.000000e+00 diff --git a/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_sigmoidal.vtu b/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_sigmoidal.vtu index 5526d402466d..a86b2420840e 100644 --- a/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_sigmoidal.vtu +++ b/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_sigmoidal.vtu @@ -3,7 +3,7 @@ - -5.000000e-01 -5.000000e-01 0.000000e+00 -2.961943e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 -3.070824e-01 6.389248e-02 -2.710893e-01 -3.679346e-01 3.282041e-02 -3.220885e-01 -2.138442e-01 1.579471e-01 -8.425341e-02 -5.000000e-01 0.000000e+00 -5.000000e-01 -1.190794e-01 2.327001e-01 -1.427550e-01 -2.036670e-01 1.587254e-01 -3.367918e-02 -3.646036e-01 3.474723e-02 -2.936288e-01 -6.024280e-02 2.280798e-01 1.199989e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 8.559378e-02 2.458009e-01 6.632135e-02 -1.960239e-01 1.456686e-01 -4.158755e-02 -2.942211e-02 2.123580e-01 1.706852e-01 -3.570974e-01 3.202384e-02 -2.020774e-01 1.419972e-01 2.249515e-01 -5.000000e-01 2.543348e-01 2.298799e-01 -3.399030e-01 2.638923e-01 2.365963e-01 3.246785e-01 -5.000000e-01 0.000000e+00 1.635995e-01 -2.113480e-02 1.653995e-01 2.698530e-01 -1.855443e-01 9.146799e-02 4.150088e-02 1.567550e-01 2.058167e-01 -1.967980e-01 3.018647e-01 2.251813e-01 3.746200e-01 -3.486372e-01 2.585984e-02 -7.966175e-02 2.828160e-01 2.187265e-01 -5.000000e-01 3.894313e-01 2.361269e-01 -3.976151e-01 4.025910e-01 2.376766e-01 -2.415572e-01 4.029806e-01 2.317340e-01 2.708605e-02 3.057637e-01 2.088328e-01 3.573303e-01 -1.642538e-02 5.068238e-02 -1.346532e-01 4.030807e-01 2.220682e-01 2.805837e-01 1.373809e-01 9.572561e-02 1.280589e-01 2.840759e-01 1.710313e-01 5.248984e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 5.000000e-01 2.193098e-01 -3.989868e-01 5.000000e-01 2.036441e-01 -2.625817e-02 4.034426e-01 1.957128e-01 -2.946243e-01 5.000000e-01 2.051985e-01 5.304011e-01 -3.026241e-01 0.000000e+00 -1.890200e-01 5.000000e-01 1.893594e-01 7.468893e-02 4.034414e-01 1.893747e-01 2.479810e-01 2.994380e-01 1.113288e-01 -8.481192e-02 5.000000e-01 1.850986e-01 5.331493e-01 -1.061236e-01 0.000000e+00 1.774451e-01 4.034666e-01 1.497197e-01 2.198726e-02 5.000000e-01 1.813930e-01 3.747089e-01 2.677468e-01 3.136313e-02 1.234675e-01 5.000000e-01 1.593729e-01 5.329600e-01 9.622950e-02 0.000000e+00 2.781282e-01 4.038703e-01 6.797017e-02 2.232866e-01 5.000000e-01 8.535446e-02 5.311495e-01 2.585477e-01 0.000000e+00 4.283062e-01 4.033266e-01 1.274614e-02 3.254498e-01 5.000000e-01 4.389874e-02 5.281597e-01 3.905607e-01 0.000000e+00 4.245887e-01 5.000000e-01 9.045338e-03 5.264592e-01 5.000000e-01 0.000000e+00 + -5.000000e-01 -5.000000e-01 0.000000e+00 -2.954690e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 -3.076218e-01 6.730670e-02 -2.698146e-01 -3.684091e-01 3.682268e-02 -3.210687e-01 -2.152692e-01 1.696515e-01 -8.165576e-02 -5.000000e-01 0.000000e+00 -5.000000e-01 -1.201263e-01 2.427572e-01 -1.393353e-01 -2.057058e-01 1.764073e-01 -2.991886e-02 -3.652212e-01 4.020307e-02 -2.923024e-01 -6.213435e-02 2.469612e-01 1.230270e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 8.486384e-02 2.546585e-01 7.102194e-02 -1.981571e-01 1.665123e-01 -3.725551e-02 -3.157286e-02 2.356577e-01 1.753316e-01 -3.578146e-01 3.830592e-02 -1.995909e-01 1.408093e-01 2.447731e-01 -5.000000e-01 2.542415e-01 2.301170e-01 -3.392484e-01 2.635720e-01 2.484821e-01 3.289313e-01 -5.000000e-01 0.000000e+00 1.686987e-01 -2.344447e-02 1.899916e-01 2.752834e-01 -1.876647e-01 1.105251e-01 4.651544e-02 1.553755e-01 2.299026e-01 -1.946200e-01 3.014690e-01 2.421528e-01 3.789940e-01 -3.494305e-01 3.224430e-02 -7.595017e-02 2.822785e-01 2.385466e-01 -5.000000e-01 3.894072e-01 2.360903e-01 -3.974708e-01 4.025171e-01 2.427420e-01 -2.400169e-01 4.028732e-01 2.438698e-01 3.160794e-02 3.053247e-01 2.304882e-01 3.629834e-01 -1.880867e-02 6.147739e-02 -1.319979e-01 4.029774e-01 2.357441e-01 2.863519e-01 1.357811e-01 1.110552e-01 1.332429e-01 2.834209e-01 1.937152e-01 5.281389e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 5.000000e-01 2.152277e-01 -3.988510e-01 5.000000e-01 2.008792e-01 -2.211396e-02 4.033233e-01 2.138188e-01 -2.937882e-01 5.000000e-01 2.101694e-01 5.357141e-01 -3.036836e-01 0.000000e+00 -1.873007e-01 5.000000e-01 1.956806e-01 7.894423e-02 4.033102e-01 2.088962e-01 2.533139e-01 2.989023e-01 1.271129e-01 -8.245013e-02 5.000000e-01 1.928728e-01 5.387344e-01 -1.085301e-01 0.000000e+00 1.823984e-01 4.033293e-01 1.680583e-01 2.526017e-02 5.000000e-01 1.922700e-01 3.801274e-01 2.670541e-01 3.722506e-02 1.270189e-01 5.000000e-01 1.712776e-01 5.382499e-01 9.470425e-02 0.000000e+00 2.828839e-01 4.037465e-01 7.916664e-02 2.266649e-01 5.000000e-01 9.571167e-02 5.364034e-01 2.580094e-01 0.000000e+00 4.331546e-01 4.032447e-01 1.492143e-02 3.292619e-01 5.000000e-01 4.987022e-02 5.324171e-01 3.904917e-01 0.000000e+00 4.279950e-01 5.000000e-01 1.038714e-02 5.300883e-01 5.000000e-01 0.000000e+00 diff --git a/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_sigmoidal_cloud_mesh.vtu b/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_sigmoidal_cloud_mesh.vtu index c1fee8c3bc08..94d1c9e76e11 100644 --- a/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_sigmoidal_cloud_mesh.vtu +++ b/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_sigmoidal_cloud_mesh.vtu @@ -3,7 +3,7 @@ - -5.000000e-01 -5.000000e-01 0.000000e+00 -2.929923e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 -3.201494e-01 9.462072e-02 -2.662187e-01 -3.738052e-01 4.520345e-02 -3.192065e-01 -2.389770e-01 2.114700e-01 -7.137459e-02 -5.000000e-01 0.000000e+00 -5.000000e-01 -1.504873e-01 3.076450e-01 -1.318939e-01 -2.274113e-01 2.152750e-01 -1.869972e-02 -3.703914e-01 4.673946e-02 -2.886095e-01 -8.288689e-02 3.382304e-01 1.393438e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 7.202739e-02 3.462325e-01 8.988429e-02 -2.141406e-01 1.911282e-01 -1.745100e-02 -4.697009e-02 3.206695e-01 1.942056e-01 -3.616797e-01 4.286300e-02 -1.913550e-01 1.345223e-01 3.243611e-01 -5.000000e-01 2.507794e-01 3.388251e-01 -3.362954e-01 2.603596e-01 3.360584e-01 3.512003e-01 -5.000000e-01 0.000000e+00 1.973595e-01 -3.297214e-02 2.360385e-01 3.003216e-01 -1.974321e-01 1.243422e-01 6.818244e-02 1.519563e-01 2.913132e-01 -1.839958e-01 3.003445e-01 3.156089e-01 4.025091e-01 -3.524456e-01 3.702279e-02 -6.068592e-02 2.811153e-01 3.056838e-01 -5.000000e-01 3.889778e-01 3.390485e-01 -3.962334e-01 4.022558e-01 3.340615e-01 -2.313558e-01 4.025169e-01 3.216266e-01 5.204180e-02 3.047941e-01 2.865577e-01 3.945260e-01 -2.505335e-02 7.126845e-02 -1.176785e-01 4.027081e-01 3.077951e-01 3.140964e-01 1.345393e-01 1.277096e-01 1.556782e-01 2.827242e-01 2.426690e-01 5.526046e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 5.000000e-01 3.355202e-01 -3.973838e-01 5.000000e-01 3.275357e-01 -4.767212e-03 4.030576e-01 2.859749e-01 -2.877968e-01 5.000000e-01 3.197776e-01 5.612722e-01 -3.065697e-01 0.000000e+00 -1.737573e-01 5.000000e-01 3.036881e-01 1.004235e-01 4.031141e-01 2.669496e-01 2.787259e-01 2.985828e-01 1.580002e-01 -6.309599e-02 5.000000e-01 2.943479e-01 5.683802e-01 -1.137751e-01 0.000000e+00 2.064581e-01 4.032120e-01 2.118134e-01 4.809829e-02 5.000000e-01 2.769805e-01 4.095707e-01 2.663091e-01 4.846368e-02 1.531911e-01 5.000000e-01 2.364388e-01 5.700729e-01 9.241886e-02 0.000000e+00 3.111695e-01 4.035230e-01 1.213958e-01 2.557911e-01 5.000000e-01 1.651439e-01 5.689338e-01 2.574772e-01 0.000000e+00 4.642457e-01 4.031836e-01 1.991678e-02 3.610078e-01 5.000000e-01 7.837617e-02 5.670536e-01 3.903282e-01 0.000000e+00 4.636742e-01 5.000000e-01 1.820048e-02 5.655497e-01 5.000000e-01 0.000000e+00 + -5.000000e-01 -5.000000e-01 0.000000e+00 -2.928662e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 -3.196572e-01 9.440912e-02 -2.654477e-01 -3.741035e-01 4.777782e-02 -3.187021e-01 -2.387544e-01 2.155435e-01 -7.001264e-02 -5.000000e-01 0.000000e+00 -5.000000e-01 -1.473493e-01 3.012083e-01 -1.296464e-01 -2.296432e-01 2.291548e-01 -1.636555e-02 -3.710580e-01 5.116060e-02 -2.876728e-01 -8.310409e-02 3.472872e-01 1.411522e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 7.337988e-02 3.385913e-01 9.405021e-02 -2.176542e-01 2.147340e-01 -1.387309e-02 -4.876027e-02 3.427513e-01 1.973531e-01 -3.627544e-01 4.899897e-02 -1.898728e-01 1.345806e-01 3.330873e-01 -5.000000e-01 2.515355e-01 3.270788e-01 -3.359347e-01 2.607184e-01 3.374378e-01 3.540190e-01 -5.000000e-01 0.000000e+00 2.022820e-01 -3.595737e-02 2.655856e-01 3.046035e-01 -2.011431e-01 1.455754e-01 7.198542e-02 1.511903e-01 3.110066e-01 -1.825121e-01 3.004650e-01 3.226735e-01 4.059908e-01 -3.538270e-01 4.439707e-02 -5.823105e-02 2.812785e-01 3.150987e-01 -5.000000e-01 3.891111e-01 3.267258e-01 -3.961261e-01 4.023486e-01 3.307730e-01 -2.304414e-01 4.025753e-01 3.261115e-01 5.498576e-02 3.046761e-01 3.023393e-01 3.991849e-01 -2.817136e-02 8.259695e-02 -1.161994e-01 4.027647e-01 3.141205e-01 3.188636e-01 1.334181e-01 1.420594e-01 1.592942e-01 2.824590e-01 2.610115e-01 5.535213e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 5.000000e-01 3.224182e-01 -3.973126e-01 5.000000e-01 3.209079e-01 -2.104780e-03 4.030529e-01 2.957158e-01 -2.872629e-01 5.000000e-01 3.201875e-01 5.637316e-01 -3.082319e-01 0.000000e+00 -1.724717e-01 5.000000e-01 3.070889e-01 1.034430e-01 4.030980e-01 2.799994e-01 2.825953e-01 2.983075e-01 1.724221e-01 -6.128498e-02 5.000000e-01 2.988654e-01 5.721223e-01 -1.174447e-01 0.000000e+00 2.099742e-01 4.032024e-01 2.264272e-01 5.068848e-02 5.000000e-01 2.867736e-01 4.139670e-01 2.658418e-01 5.427942e-02 1.560699e-01 5.000000e-01 2.487219e-01 5.739391e-01 9.085196e-02 0.000000e+00 3.150009e-01 4.034570e-01 1.325200e-01 2.590307e-01 5.000000e-01 1.760165e-01 5.726293e-01 2.573698e-01 0.000000e+00 4.681638e-01 4.031980e-01 2.200160e-02 3.647395e-01 5.000000e-01 8.505322e-02 5.707811e-01 3.903147e-01 0.000000e+00 4.672538e-01 5.000000e-01 1.991320e-02 5.686700e-01 5.000000e-01 0.000000e+00 diff --git a/applications/OptimizationApplication/tests/filtering/explicit_filters_tests.py b/applications/OptimizationApplication/tests/filtering/explicit_filters_tests.py index 452b2b782db7..36c10508c249 100644 --- a/applications/OptimizationApplication/tests/filtering/explicit_filters_tests.py +++ b/applications/OptimizationApplication/tests/filtering/explicit_filters_tests.py @@ -236,12 +236,6 @@ def __RunTestCase(self, filter_function_type: str, damping_function_type: str, r vm_filter.SetComponentDataView(ComponentDataView("test", self.optimization_problem)) vm_filter.Initialize() - nodal_neighbours = Kratos.TensorAdaptors.NodalNeighbourCountTensorAdaptor(self.model_part.Nodes, self.model_part.Elements) - nodal_neighbours.CollectData() - - nodal_neighbours_exp = Kratos.Expression.NodalExpression(self.model_part) - KratosOA.ExpressionUtils.ComputeNumberOfNeighbourElements(nodal_neighbours_exp) - step_size = 5e-2 for i in range(10): Kratos.NormalCalculationUtils().CalculateNormalsInElements(self.model_part, Kratos.NORMAL) @@ -253,13 +247,7 @@ def __RunTestCase(self, filter_function_type: str, damping_function_type: str, r physical_element_gradient = Kratos.TensorAdaptors.DoubleTensorAdaptor(element_ta) physical_element_gradient.data = element_ta.data * domain_size_ta.data[:, None] # row wise scaling - - physical_element_gradient_exp = Kratos.Expression.ElementExpression(self.model_part) - Kratos.Expression.CArrayExpressionIO.Read(physical_element_gradient_exp, physical_element_gradient.data) - physical_space_gradient_exp = Kratos.Expression.NodalExpression(self.model_part) - KratosOA.ExpressionUtils.MapContainerVariableToNodalVariable(physical_space_gradient_exp, physical_element_gradient_exp, nodal_neighbours_exp) - physical_space_gradient = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, Kratos.NORMAL) - physical_space_gradient.data[:] = physical_space_gradient_exp.Evaluate() + physical_space_gradient = KratosOA.OptimizationUtils.MapContainerDataToNodalData(physical_element_gradient, self.model_part.Nodes) control_space_gradient = vm_filter.BackwardFilterField(physical_space_gradient) control_update = Kratos.TensorAdaptors.DoubleTensorAdaptor(control_space_gradient) From ae94241e491eaec21af84d01eba7d7aabd029140 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Wed, 4 Feb 2026 14:33:16 +0100 Subject: [PATCH 037/116] fix implicit filters --- .../filtering/helmholtz_analysis.py | 85 +++++++++--------- .../tests/filtering/implicit_filters_tests.py | 86 ++++++++++--------- 2 files changed, 86 insertions(+), 85 deletions(-) diff --git a/applications/OptimizationApplication/python_scripts/filtering/helmholtz_analysis.py b/applications/OptimizationApplication/python_scripts/filtering/helmholtz_analysis.py index c0e9894749e4..5c7d087fe9ac 100644 --- a/applications/OptimizationApplication/python_scripts/filtering/helmholtz_analysis.py +++ b/applications/OptimizationApplication/python_scripts/filtering/helmholtz_analysis.py @@ -1,10 +1,9 @@ -from typing import Any +from typing import Any, Optional # Importing Kratos import KratosMultiphysics as KM import KratosMultiphysics.OptimizationApplication as KOA import KratosMultiphysics.OptimizationApplication.filtering.python_solvers_wrapper_implicit_filters as implicit_filter_solvers -from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import ContainerExpressionTypes # Importing the base class from KratosMultiphysics.analysis_stage import AnalysisStage @@ -16,8 +15,8 @@ class HelmholtzAnalysis(AnalysisStage): """ def __init__(self, model: KM.Model, project_parameters: KM.Parameters): super().__init__(model, project_parameters) - self.__source_data: ContainerExpressionTypes = None - self.__neighbour_entities: 'dict[Any, KM.Expression.NodalExpression]' = {} + self.__source_data: 'Optional[KM.TensorAdaptors.DoubleTensorAdaptor]' = None + self.__neighbour_entities: 'dict[Any, KM.TensorAdaptors.IntTensorAdaptor]' = {} #### Internal functions #### def _CreateSolver(self): @@ -52,40 +51,39 @@ def RunSolver(self): self._GetSolver().SolveSolutionStep() self.FinalizeSolutionStep() - def FilterField(self, unfiltered_field: ContainerExpressionTypes) -> ContainerExpressionTypes: + def FilterField(self, unfiltered_field: KM.TensorAdaptors.DoubleTensorAdaptor) -> KM.TensorAdaptors.DoubleTensorAdaptor: - self.__AssignDataExpressionToNodalSource(unfiltered_field) + self.__AssignTensorDataToNodalSource(unfiltered_field) self._SetSolverMode(False) self._SetHelmHoltzSourceMode(False) self.RunSolver() - return self.__AssignNodalSolutionToDataExpression() + return self.__AssignNodalSolutionToTensorData() - def FilterIntegratedField(self, unfiltered_field: ContainerExpressionTypes) -> ContainerExpressionTypes: + def FilterIntegratedField(self, unfiltered_field: KM.TensorAdaptors.DoubleTensorAdaptor) -> KM.TensorAdaptors.DoubleTensorAdaptor: - self.__AssignDataExpressionToNodalSource(unfiltered_field) + self.__AssignTensorDataToNodalSource(unfiltered_field) self._SetSolverMode(False) self._SetHelmHoltzSourceMode(True) self.RunSolver() - return self.__AssignNodalSolutionToDataExpression() + return self.__AssignNodalSolutionToTensorData() - def UnFilterField(self, filtered_field: ContainerExpressionTypes) -> ContainerExpressionTypes: + def UnFilterField(self, filtered_field: KM.TensorAdaptors.DoubleTensorAdaptor) -> KM.TensorAdaptors.DoubleTensorAdaptor: - self.__AssignDataExpressionToNodalSource(filtered_field) + self.__AssignTensorDataToNodalSource(filtered_field) self._SetSolverMode(True) self._SetHelmHoltzSourceMode(False) self.RunSolver() - return self.__AssignNodalSolutionToDataExpression() + return self.__AssignNodalSolutionToTensorData() - def AssignExpressionDataToNodalSolution(self, data_exp: ContainerExpressionTypes) -> None: - mapped_values = KM.Expression.NodalExpression(data_exp.GetModelPart()) - if isinstance(data_exp, KM.Expression.NodalExpression): - mapped_values = data_exp - else: - KOA.ExpressionUtils.MapContainerVariableToNodalVariable(mapped_values, data_exp, self.__GetNeighbourEntities(data_exp)) - KM.Expression.VariableExpressionIO.Write(mapped_values, self._GetSolver().GetSolvingVariable(), True) + def AssignTensorDataToNodalSolution(self, data_exp: KM.TensorAdaptors.DoubleTensorAdaptor) -> None: + ta = KM.TensorAdaptors.DoubleTensorAdaptor(data_exp, copy=False) + if not isinstance(ta.GetContainer(), KM.NodesArray): + neighbours = self.__GetNeighbourEntities(data_exp) + ta = KOA.OptimizationUtils.MapContainerDataToNodalData(data_exp, neighbours.GetContainer()) + KM.TensorAdaptors.HistoricalVariableTensorAdaptor(ta, self._GetSolver().GetSolvingVariable(), copy=False).StoreData() - def __AssignDataExpressionToNodalSource(self, data_exp: ContainerExpressionTypes): - self.__source_data = data_exp + def __AssignTensorDataToNodalSource(self, data_exp: KM.TensorAdaptors.DoubleTensorAdaptor): + self.__source_data = KM.TensorAdaptors.DoubleTensorAdaptor(data_exp) # it is better to work on the model part of the data_exp rather than the internal # model part created with ConnectivityPreserveModelPart because, then all the outputs will @@ -93,17 +91,16 @@ def __AssignDataExpressionToNodalSource(self, data_exp: ContainerExpressionTypes # the helmholtz model part and the original model part. This is safer because the helmholtz modelpart # is created using the ConnectivityPreserveModeller which preserves the same nodes and condition/element # data containers. - mapped_values = KM.Expression.NodalExpression(data_exp.GetModelPart()) - if isinstance(data_exp, KM.Expression.NodalExpression): - mapped_values = data_exp - else: - KOA.ExpressionUtils.MapContainerVariableToNodalVariable(mapped_values, data_exp, self.__GetNeighbourEntities(data_exp)) - KM.Expression.VariableExpressionIO.Write(mapped_values, self._GetSolver().GetSourceVariable(), False) + ta = KM.TensorAdaptors.DoubleTensorAdaptor(data_exp, copy=False) + if not isinstance(ta.GetContainer(), KM.NodesArray): + neighbours = self.__GetNeighbourEntities(data_exp) + ta = KOA.OptimizationUtils.MapContainerDataToNodalData(data_exp, neighbours.GetContainer()) + KM.TensorAdaptors.VariableTensorAdaptor(ta, self._GetSolver().GetSourceVariable(), copy=False).StoreData() - def __AssignNodalSolutionToDataExpression(self) -> ContainerExpressionTypes: + def __AssignNodalSolutionToTensorData(self) -> KM.TensorAdaptors.DoubleTensorAdaptor: if self.__source_data is None: - raise RuntimeError("The __AssignDataExpressionToNodalSource should be called first.") + raise RuntimeError("The __AssignTensorDataToNodalSource should be called first.") # it is better to work on the model part of the data_exp rather than the internal # model part created with ConnectivityPreserveModelPart because, then all the outputs will @@ -111,27 +108,29 @@ def __AssignNodalSolutionToDataExpression(self) -> ContainerExpressionTypes: # the helmholtz model part and the original model part. This is safer because the helmholtz modelpart # is created using the ConnectivityPreserveModeller which preserves the same nodes and condition/element # data containers. - nodal_solution_field = KM.Expression.NodalExpression(self.__source_data.GetModelPart()) + neighbours = self.__GetNeighbourEntities(self.__source_data) + solution = KM.TensorAdaptors.HistoricalVariableTensorAdaptor(neighbours.GetContainer(), self._GetSolver().GetSolvingVariable()) + solution.CollectData() - KM.Expression.VariableExpressionIO.Read(nodal_solution_field, self._GetSolver().GetSolvingVariable(), True) - - if isinstance(self.__source_data, KM.Expression.NodalExpression): - return nodal_solution_field.Clone() + if isinstance(self.__source_data.GetContainer(), KM.NodesArray): + return KM.TensorAdaptors.DoubleTensorAdaptor(solution, copy=False) else: - mapped_entity_solution_field = self.__source_data.Clone() - KOA.ExpressionUtils.MapNodalVariableToContainerVariable(mapped_entity_solution_field, nodal_solution_field) - return mapped_entity_solution_field + return KOA.OptimizationUtils.MapNodalDataToContainerData(solution, self.__source_data.GetContainer(), neighbours) - def __GetNeighbourEntities(self, data_exp: ContainerExpressionTypes) -> ContainerExpressionTypes: + def __GetNeighbourEntities(self, data_exp: KM.TensorAdaptors.DoubleTensorAdaptor) -> KM.TensorAdaptors.IntTensorAdaptor: # following makes the number of neighbours computation to be executed once # per given container, hence if the mesh element/connectivity changes # this computation needs to be redone. Especially in the case if MMG is # used for re-meshing. key = data_exp.GetContainer() if key not in self.__neighbour_entities.keys(): - self.__neighbour_entities[key] = KM.Expression.NodalExpression(data_exp.GetModelPart()) - if isinstance(data_exp, KM.Expression.ElementExpression): - KOA.ExpressionUtils.ComputeNumberOfNeighbourElements(self.__neighbour_entities[key]) + if not isinstance(key, KM.NodesArray): + ta = KM.TensorAdaptors.NodalNeighbourCountTensorAdaptor(self._GetSolver().GetComputingModelPart().Nodes, data_exp.GetContainer()) + ta.CollectData() + self.__neighbour_entities[key] = ta else: - KOA.ExpressionUtils.ComputeNumberOfNeighbourConditions(self.__neighbour_entities[key]) + ta = KM.TensorAdaptors.IntTensorAdaptor(key, KM.IntNDData([len(key)]), copy=False) + ta.data[:] = 1 + self.__neighbour_entities[key] = ta + return self.__neighbour_entities[key] \ No newline at end of file diff --git a/applications/OptimizationApplication/tests/filtering/implicit_filters_tests.py b/applications/OptimizationApplication/tests/filtering/implicit_filters_tests.py index 83414cfd389f..856b62fb6ab6 100644 --- a/applications/OptimizationApplication/tests/filtering/implicit_filters_tests.py +++ b/applications/OptimizationApplication/tests/filtering/implicit_filters_tests.py @@ -1,3 +1,5 @@ +import numpy + import KratosMultiphysics as KM from KratosMultiphysics.OptimizationApplication.filtering.helmholtz_analysis import HelmholtzAnalysis from KratosMultiphysics.testing.utilities import ReadModelPart @@ -252,11 +254,11 @@ def test_scalar_solid_filter(self): # to get the expected result. self.solid_scalar_filter.Initialize() - unfiltered_uniform_field_nodal = KM.Expression.NodalExpression(self.solid_scalar_model_part) - KM.Expression.LiteralExpressionIO.SetData(unfiltered_uniform_field_nodal, 1.0) + unfiltered_uniform_field_nodal = KM.TensorAdaptors.VariableTensorAdaptor(self.solid_scalar_model_part.Nodes, KM.PRESSURE) + unfiltered_uniform_field_nodal.data[:] = 1.0 filtered_field = self.solid_scalar_filter.FilterField(unfiltered_uniform_field_nodal) - self.assertAlmostEqual(KM.Expression.Utils.NormL2(filtered_field), 3.741657, 4) + self.assertAlmostEqual(numpy.linalg.norm(filtered_field.data), 3.741657, 4) for node in self.solid_scalar_model_part.Nodes: node.SetValue(KM.NODAL_VOLUME, 0) @@ -265,13 +267,13 @@ def test_scalar_solid_filter(self): for node in element.GetNodes(): node.SetValue(KM.NODAL_VOLUME, node.GetValue(KM.NODAL_VOLUME)+element.GetGeometry().Volume()/4.0) - nodal_volume = KM.Expression.NodalExpression(self.solid_scalar_model_part) - KM.Expression.VariableExpressionIO.Read(nodal_volume, KM.NODAL_VOLUME, False) + nodal_volume = KM.TensorAdaptors.VariableTensorAdaptor(self.solid_scalar_model_part.Nodes, KM.NODAL_VOLUME) + nodal_volume.CollectData() filtered_field = self.solid_scalar_filter.FilterIntegratedField(nodal_volume) - self.assertAlmostEqual(KM.Expression.Utils.NormL2(filtered_field), 3.741657, 4) + self.assertAlmostEqual(numpy.linalg.norm(filtered_field.data), 3.741657, 4) filtered_field = self.solid_scalar_filter.UnFilterField(unfiltered_uniform_field_nodal) - self.assertAlmostEqual(KM.Expression.Utils.NormL2(filtered_field), 3.741657, 4) + self.assertAlmostEqual(numpy.linalg.norm(filtered_field.data), 3.741657, 4) self.solid_scalar_filter.Finalize() @@ -282,11 +284,11 @@ def test_vector_solid_filter(self): # to get the expected result. self.solid_vector_filter.Initialize() - unfiltered_uniform_field_nodal = KM.Expression.NodalExpression(self.solid_vector_model_part) - KM.Expression.LiteralExpressionIO.SetData(unfiltered_uniform_field_nodal, KM.Array3([1, 1, 1])) + unfiltered_uniform_field_nodal = KM.TensorAdaptors.VariableTensorAdaptor(self.solid_vector_model_part.Nodes, KM.VELOCITY) + unfiltered_uniform_field_nodal.data[:] = 1.0 filtered_field = self.solid_vector_filter.FilterField(unfiltered_uniform_field_nodal) - self.assertAlmostEqual(KM.Expression.Utils.NormL2(filtered_field), 6.48074, 4) + self.assertAlmostEqual(numpy.linalg.norm(filtered_field.data), 6.48074, 4) for node in self.solid_vector_model_part.Nodes: node.SetValue(KM.VELOCITY, KM.Array3([0, 0, 0])) @@ -297,13 +299,13 @@ def test_vector_solid_filter(self): node.SetValue(KM.VELOCITY_Y, node.GetValue(KM.VELOCITY_Y)+element.GetGeometry().Volume()/4.0) node.SetValue(KM.VELOCITY_Z, node.GetValue(KM.VELOCITY_Z)+element.GetGeometry().Volume()/4.0) - nodal_volume = KM.Expression.NodalExpression(self.solid_vector_model_part) - KM.Expression.VariableExpressionIO.Read(nodal_volume, KM.VELOCITY, False) + nodal_volume = KM.TensorAdaptors.VariableTensorAdaptor(self.solid_vector_model_part.Nodes, KM.VELOCITY) + nodal_volume.CollectData() filtered_field = self.solid_vector_filter.FilterIntegratedField(nodal_volume) - self.assertAlmostEqual(KM.Expression.Utils.NormL2(filtered_field), 6.48074, 4) + self.assertAlmostEqual(numpy.linalg.norm(filtered_field.data), 6.48074, 4) filtered_field = self.solid_vector_filter.UnFilterField(unfiltered_uniform_field_nodal) - self.assertAlmostEqual(KM.Expression.Utils.NormL2(filtered_field), 6.48074, 4) + self.assertAlmostEqual(numpy.linalg.norm(filtered_field.data), 6.48074, 4) def test_scalar_closed_shell_filter(self): # initialization of the filter done here so that filtering radius is set. @@ -312,11 +314,11 @@ def test_scalar_closed_shell_filter(self): # to get the expected result. self.closed_shell_scalar_filter.Initialize() - unfiltered_uniform_field_nodal = KM.Expression.NodalExpression(self.closed_shell_model_part) - KM.Expression.LiteralExpressionIO.SetData(unfiltered_uniform_field_nodal, 1.0) + unfiltered_uniform_field_nodal = KM.TensorAdaptors.VariableTensorAdaptor(self.closed_shell_model_part.Nodes, KM.PRESSURE) + unfiltered_uniform_field_nodal.data[:] = 1.0 filtered_field = self.closed_shell_scalar_filter.FilterField(unfiltered_uniform_field_nodal) - self.assertAlmostEqual(KM.Expression.Utils.NormL2(filtered_field), 2.8284271247, 4) + self.assertAlmostEqual(numpy.linalg.norm(filtered_field.data), 2.8284271247, 4) for node in self.closed_shell_model_part.Nodes: node.SetValue(KM.NODAL_AREA, 0) @@ -325,13 +327,13 @@ def test_scalar_closed_shell_filter(self): for node in element.GetNodes(): node.SetValue(KM.NODAL_AREA, node.GetValue(KM.NODAL_AREA)+element.GetGeometry().Area()/4.0) - nodal_area = KM.Expression.NodalExpression(self.closed_shell_model_part) - KM.Expression.VariableExpressionIO.Read(nodal_area, KM.NODAL_AREA, False) + nodal_area = KM.TensorAdaptors.VariableTensorAdaptor(self.closed_shell_model_part.Nodes, KM.NODAL_AREA) + nodal_area.CollectData() filtered_field = self.closed_shell_scalar_filter.FilterIntegratedField(nodal_area) - self.assertAlmostEqual(KM.Expression.Utils.NormL2(filtered_field), 2.8284271247, 4) + self.assertAlmostEqual(numpy.linalg.norm(filtered_field.data), 2.8284271247, 4) filtered_field = self.closed_shell_scalar_filter.UnFilterField(unfiltered_uniform_field_nodal) - self.assertAlmostEqual(KM.Expression.Utils.NormL2(filtered_field), 2.8284271247, 4) + self.assertAlmostEqual(numpy.linalg.norm(filtered_field.data), 2.8284271247, 4) def test_vector_shell_filter(self): # initialization of the filter done here so that filtering radius is set. @@ -340,15 +342,15 @@ def test_vector_shell_filter(self): # to get the expected result. self.shell_vector_filter.Initialize() - unfiltered_uniform_field_nodal = KM.Expression.NodalExpression(self.shell_model_part) - KM.Expression.LiteralExpressionIO.SetData(unfiltered_uniform_field_nodal, KM.Array3([1, 1, 1])) + unfiltered_uniform_field_nodal = KM.TensorAdaptors.VariableTensorAdaptor(self.shell_model_part.Nodes, KM.VELOCITY) + unfiltered_uniform_field_nodal.data[:] = 1.0 filtered_field = self.shell_vector_filter.UnFilterField(unfiltered_uniform_field_nodal) filtered_field = self.shell_vector_filter.FilterField(filtered_field) - self.assertAlmostEqual(KM.Expression.Utils.NormL2(filtered_field), 5.196153341144455, 4) + self.assertAlmostEqual(numpy.linalg.norm(filtered_field.data), 5.196153341144455, 4) filtered_field = self.shell_vector_filter.FilterField(unfiltered_uniform_field_nodal) - self.assertAlmostEqual(KM.Expression.Utils.NormL2(filtered_field), 5.1961524, 4) + self.assertAlmostEqual(numpy.linalg.norm(filtered_field.data), 5.1961524, 4) for node in self.shell_model_part.Nodes: node.SetValue(KM.VELOCITY, KM.Array3([0, 0, 0])) @@ -359,11 +361,11 @@ def test_vector_shell_filter(self): node.SetValue(KM.VELOCITY_Y, node.GetValue(KM.VELOCITY_Y)+element.GetGeometry().Area()/3.0) node.SetValue(KM.VELOCITY_Z, node.GetValue(KM.VELOCITY_Z)+element.GetGeometry().Area()/3.0) - nodal_area = KM.Expression.NodalExpression(self.shell_model_part) - KM.Expression.VariableExpressionIO.Read(nodal_area, KM.VELOCITY, False) + nodal_area = KM.TensorAdaptors.VariableTensorAdaptor(self.shell_model_part.Nodes, KM.VELOCITY) + nodal_area.CollectData() filtered_field = self.shell_vector_filter.FilterIntegratedField(nodal_area) - self.assertAlmostEqual(KM.Expression.Utils.NormL2(filtered_field), 5.196118198546968, 4) + self.assertAlmostEqual(numpy.linalg.norm(filtered_field.data), 5.196118198546968, 4) def test_bulk_surface_shape(self): # initialization of the filter done here so that filtering radius is set. @@ -372,11 +374,11 @@ def test_bulk_surface_shape(self): # to get the expected result. self.bulk_surface_filter.Initialize() - unfiltered_uniform_field_nodal = KM.Expression.NodalExpression(self.solid_bulk_surface_model_part) - KM.Expression.LiteralExpressionIO.SetData(unfiltered_uniform_field_nodal, KM.Array3([1, 1, 1])) + unfiltered_uniform_field_nodal = KM.TensorAdaptors.VariableTensorAdaptor(self.solid_bulk_surface_model_part.Nodes, KM.VELOCITY) + unfiltered_uniform_field_nodal.data[:] = 1.0 filtered_field = self.bulk_surface_filter.FilterField(unfiltered_uniform_field_nodal) - self.assertAlmostEqual(KM.Expression.Utils.NormL2(filtered_field), 6.4807406, 4) + self.assertAlmostEqual(numpy.linalg.norm(filtered_field.data), 6.4807406, 4) for node in self.solid_bulk_surface_model_part.Nodes: node.SetValue(KM.VELOCITY, KM.Array3([0, 0, 0])) @@ -387,34 +389,34 @@ def test_bulk_surface_shape(self): node.SetValue(KM.VELOCITY_Y, node.GetValue(KM.VELOCITY_Y)+element.GetGeometry().Volume()/4.0) node.SetValue(KM.VELOCITY_Z, node.GetValue(KM.VELOCITY_Z)+element.GetGeometry().Volume()/4.0) - nodal_area = KM.Expression.NodalExpression(self.solid_bulk_surface_model_part) - KM.Expression.VariableExpressionIO.Read(nodal_area, KM.VELOCITY, False) + nodal_area = KM.TensorAdaptors.VariableTensorAdaptor(self.solid_bulk_surface_model_part.Nodes, KM.VELOCITY) + nodal_area.CollectData() filtered_field = self.bulk_surface_filter.FilterIntegratedField(nodal_area) - self.assertAlmostEqual(KM.Expression.Utils.NormL2(filtered_field), 6.4807406, 4) + self.assertAlmostEqual(numpy.linalg.norm(filtered_field.data), 6.4807406, 4) filtered_field = self.bulk_surface_filter.UnFilterField(unfiltered_uniform_field_nodal) - self.assertAlmostEqual(KM.Expression.Utils.NormL2(filtered_field), 6.4807406, 4) + self.assertAlmostEqual(numpy.linalg.norm(filtered_field.data), 6.4807406, 4) def test_shape_surface_shape(self): self.shape_bulk_surface_filter.Initialize() - unfiltered_uniform_field_nodal = KM.Expression.NodalExpression(self.solid_bulk_surface_model_part) - KM.Expression.LiteralExpressionIO.SetData(unfiltered_uniform_field_nodal, KM.Array3([1, 1, 1])) + unfiltered_uniform_field_nodal = KM.TensorAdaptors.VariableTensorAdaptor(self.solid_bulk_surface_model_part.Nodes, KM.VELOCITY) + unfiltered_uniform_field_nodal.data[:] = 1.0 filtered_field = self.shape_bulk_surface_filter.FilterField(unfiltered_uniform_field_nodal) - self.assertAlmostEqual(KM.Expression.Utils.NormL2(filtered_field), 6.4807406, 4) + self.assertAlmostEqual(numpy.linalg.norm(filtered_field.data), 6.4807406, 4) self.shape_shell_surface_filter.Initialize() - unfiltered_uniform_field_nodal = KM.Expression.NodalExpression(self.shell_model_part) - KM.Expression.LiteralExpressionIO.SetData(unfiltered_uniform_field_nodal, KM.Array3([1, 1, 1])) + unfiltered_uniform_field_nodal = KM.TensorAdaptors.VariableTensorAdaptor(self.shell_model_part.Nodes, KM.VELOCITY) + unfiltered_uniform_field_nodal.data[:] = 1.0 filtered_field = self.shape_shell_surface_filter.UnFilterField(unfiltered_uniform_field_nodal) filtered_field = self.shape_shell_surface_filter.FilterField(filtered_field) - self.assertAlmostEqual(KM.Expression.Utils.NormL2(filtered_field), 5.196153341144455, 4) + self.assertAlmostEqual(numpy.linalg.norm(filtered_field.data), 5.196153341144455, 4) filtered_field = self.shape_shell_surface_filter.FilterField(unfiltered_uniform_field_nodal) - self.assertAlmostEqual(KM.Expression.Utils.NormL2(filtered_field), 5.1961524, 4) + self.assertAlmostEqual(numpy.linalg.norm(filtered_field.data), 5.1961524, 4) if __name__ == '__main__': KM.KratosUnittest.main() From 05202767c1be9a2e0752f0592efb86bc3ac926fb Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Wed, 4 Feb 2026 14:50:46 +0100 Subject: [PATCH 038/116] fix geometric centroid deviation response --- ...ic_centroid_deviation_response_function.py | 23 ++++++++----------- ...ic_centroid_deviation_response_function.py | 5 ++-- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/applications/OptimizationApplication/python_scripts/responses/geometric_centroid_deviation_response_function.py b/applications/OptimizationApplication/python_scripts/responses/geometric_centroid_deviation_response_function.py index c129b9011451..5b28518775db 100644 --- a/applications/OptimizationApplication/python_scripts/responses/geometric_centroid_deviation_response_function.py +++ b/applications/OptimizationApplication/python_scripts/responses/geometric_centroid_deviation_response_function.py @@ -79,24 +79,19 @@ def CalculateValue(self) -> float: self.value_array = (average_location / number_of_nodes - self.model_part_center) return self.value_array[0] ** 2 + self.value_array[1] ** 2 + self.value_array[2] ** 2 - def CalculateGradient(self, physical_variable_collective_expressions: 'dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]') -> None: - # first merge all the model parts - merged_model_part_map = ModelPartUtilities.GetMergedMap(physical_variable_collective_expressions, False) - - # now get the intersected model parts - intersected_model_part_map = ModelPartUtilities.GetIntersectedMap(self.model_part, merged_model_part_map, False) - + def CalculateGradient(self, physical_variable_combined_tensor_adaptor: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]') -> None: number_of_nodes = self.model_part.GetCommunicator().GlobalNumberOfNodes() # calculate the gradients - for physical_variable, merged_model_part in merged_model_part_map.items(): + for physical_variable, sensitivity_ta in physical_variable_combined_tensor_adaptor.items(): if physical_variable == KratosOA.SHAPE: - Kratos.VariableUtils().SetNonHistoricalVariableToZero(Kratos.SHAPE_SENSITIVITY, merged_model_part.Nodes) - Kratos.VariableUtils().SetNonHistoricalVariable(Kratos.SHAPE_SENSITIVITY, 2.0 * self.value_array / number_of_nodes, intersected_model_part_map[physical_variable].Nodes) - for container_expression in physical_variable_collective_expressions[physical_variable].GetContainerExpressions(): - if isinstance(container_expression, Kratos.Expression.NodalExpression): - Kratos.Expression.VariableExpressionIO.Read(container_expression, Kratos.SHAPE_SENSITIVITY, False) + Kratos.VariableUtils().SetNonHistoricalVariableToZero(Kratos.SHAPE_SENSITIVITY, self.model_part.Nodes) + Kratos.VariableUtils().SetNonHistoricalVariable(Kratos.SHAPE_SENSITIVITY, 2.0 * self.value_array / number_of_nodes, self.model_part.Nodes) + for sub_sensitivity_ta in sensitivity_ta.GetTensorAdaptors(): + if isinstance(sub_sensitivity_ta.GetContainer(), Kratos.NodesArray): + Kratos.TensorAdaptors.VariableTensorAdaptor(sub_sensitivity_ta, Kratos.SHAPE_SENSITIVITY, copy=False).CollectData() else: - raise RuntimeError(f"Requesting sensitivity w.r.t. SHAPE for a Container expression which is not a NodalExpression. [ Requested container expression = {container_expression} ].") + raise RuntimeError(f"Requesting sensitivity w.r.t. SHAPE for a non nodal tensor adaptor. [ Requested container tensor adaptor = {sub_sensitivity_ta} ].") + sensitivity_ta.CollectData() else: raise RuntimeError(f"Unsupported sensitivity w.r.t. {physical_variable.Name()} requested. Followings are supported sensitivity variables:\n\tSHAPE") diff --git a/applications/OptimizationApplication/tests/responses_tests/test_geometric_centroid_deviation_response_function.py b/applications/OptimizationApplication/tests/responses_tests/test_geometric_centroid_deviation_response_function.py index 5b249f3829c7..06eacc529593 100644 --- a/applications/OptimizationApplication/tests/responses_tests/test_geometric_centroid_deviation_response_function.py +++ b/applications/OptimizationApplication/tests/responses_tests/test_geometric_centroid_deviation_response_function.py @@ -39,9 +39,10 @@ def test_CalculateValue(self): self.assertAlmostEqual(self.ref_value, 0.0, 12) def test_CalculateShapeSensitivity(self): - sensitivity = KratosOA.CollectiveExpression([Kratos.Expression.NodalExpression(self.model_part)]) + sub_sensitivity = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, KratosOA.SHAPE) + sensitivity = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([sub_sensitivity]) self.response_function.CalculateGradient({KratosOA.SHAPE: sensitivity}) - Kratos.Expression.VariableExpressionIO.Write(sensitivity.GetContainerExpressions()[0], KratosOA.SHAPE, False) + sensitivity.GetTensorAdaptors()[0].StoreData() # calculate nodal shape sensitivities self._CheckSensitivity( From 206c1b1a6bb7606b0bf1012bee91f020862a73ce Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Wed, 4 Feb 2026 15:45:41 +0100 Subject: [PATCH 039/116] remove everything related to sloly to exps. --- .../add_custom_utilities_to_python.cpp | 258 ------ .../collective_expression.cpp | 275 ------- .../custom_utilities/collective_expression.h | 184 ----- ...llective_expression_arithmetic_operators.h | 53 -- .../collective_expression_io.cpp | 235 ------ .../collective_expression_io.h | 155 ---- .../container_expression_utils.cpp | 625 -------------- .../container_expression_utils.h | 350 -------- .../container_properties_data_io.h | 58 -- .../properties_variable_expression_io.cpp | 166 ---- .../properties_variable_expression_io.h | 153 ---- .../tests/test_collective_expressions.py | 761 ------------------ .../tests/test_container_expression.py | 445 ---------- .../tests/test_container_expression_utils.py | 363 --------- 14 files changed, 4081 deletions(-) delete mode 100644 applications/OptimizationApplication/custom_utilities/collective_expression.cpp delete mode 100644 applications/OptimizationApplication/custom_utilities/collective_expression.h delete mode 100644 applications/OptimizationApplication/custom_utilities/collective_expression_arithmetic_operators.h delete mode 100644 applications/OptimizationApplication/custom_utilities/collective_expression_io.cpp delete mode 100644 applications/OptimizationApplication/custom_utilities/collective_expression_io.h delete mode 100644 applications/OptimizationApplication/custom_utilities/container_expression_utils.cpp delete mode 100644 applications/OptimizationApplication/custom_utilities/container_expression_utils.h delete mode 100644 applications/OptimizationApplication/custom_utilities/container_properties_data_io.h delete mode 100644 applications/OptimizationApplication/custom_utilities/properties_variable_expression_io.cpp delete mode 100644 applications/OptimizationApplication/custom_utilities/properties_variable_expression_io.h delete mode 100644 applications/OptimizationApplication/tests/test_collective_expressions.py delete mode 100644 applications/OptimizationApplication/tests/test_container_expression.py delete mode 100644 applications/OptimizationApplication/tests/test_container_expression_utils.py diff --git a/applications/OptimizationApplication/custom_python/add_custom_utilities_to_python.cpp b/applications/OptimizationApplication/custom_python/add_custom_utilities_to_python.cpp index 56499a66898a..fd6c1cccc9ff 100644 --- a/applications/OptimizationApplication/custom_python/add_custom_utilities_to_python.cpp +++ b/applications/OptimizationApplication/custom_python/add_custom_utilities_to_python.cpp @@ -21,14 +21,10 @@ #include "python/numpy_utils.h" // Application includes -#include "custom_utilities/collective_expression.h" -#include "custom_utilities/collective_expression_io.h" -#include "custom_utilities/container_expression_utils.h" #include "custom_utilities/geometrical/opt_app_model_part_utils.h" #include "custom_utilities/geometrical/symmetry_utility.h" #include "custom_utilities/implicit_filter_utils.h" #include "custom_utilities/optimization_utils.h" -#include "custom_utilities/properties_variable_expression_io.h" // Include base h #include "add_custom_response_utilities_to_python.h" @@ -36,94 +32,10 @@ namespace Kratos { namespace Python { -namespace Detail -{ - -template -void CollectiveExpressionFromPythonArray( - CollectiveExpression& rCollectiveExpression, - const pybind11::array_t& rData, - const std::vector>& rListOfShapes, - TCArrayData rCArrayData) -{ - KRATOS_TRY - - auto r_container_expressions = rCollectiveExpression.GetContainerExpressions(); - - KRATOS_ERROR_IF(rData.ndim() == 0) << "Passed data is not compatible.\n"; - - KRATOS_ERROR_IF(r_container_expressions.size() != rListOfShapes.size()) - << "Number of container expressions in the Collective expression and list of shapes size mismatch. " - << "[ Number of container expressions = " - << r_container_expressions.size() - << ", list of shapes size = " << rListOfShapes.size() << " ].\n"; - - int required_number_of_values = 0; - for (IndexType i = 0; i < r_container_expressions.size(); ++i) { - required_number_of_values += std::visit([&rListOfShapes, i](auto& pContainerExpression){ - return pContainerExpression->GetContainer().size() * std::accumulate(rListOfShapes[i].begin(), rListOfShapes[i].end(), 1, [](const int V1, const int V2) { return V1 * V2; }); - }, r_container_expressions[i]); - } - - KRATOS_ERROR_IF_NOT(required_number_of_values == rData.size()) - << "Required number of values for the specified ContainerExpressions " - "and shapes mismatch with the values present in the rData array. [ " - "required number of values = " - << required_number_of_values << ", rData.size() = " << rData.size() - << ", shapes = " << rListOfShapes - << ", collective expression = " << rCollectiveExpression - << " ].\n"; - - // create c style double pointer from std::vector list for shapes. - int const** p_list_of_shapes = new int const*[rListOfShapes.size()]; - std::transform(rListOfShapes.begin(), rListOfShapes.end(), p_list_of_shapes, - [](const auto& rShape) { return rShape.data(); }); - - // create c style double pointer for sizes of std::vector list. - int* p_list_of_shape_dimensions = new int[rListOfShapes.size()]; - std::transform(rListOfShapes.begin(), rListOfShapes.end(), p_list_of_shape_dimensions, - [](const auto& rShape) { return rShape.size(); }); - - // create c style double pointer for number of entities in each container expression. - int* p_list_of_number_of_entities_in_container = new int[rListOfShapes.size()]; - std::transform(r_container_expressions.begin(), r_container_expressions.end(), p_list_of_number_of_entities_in_container, - [](const auto& pContainerExpressionVariant) { return std::visit([](const auto pContainerExpression) { return pContainerExpression->GetContainer().size(); }, pContainerExpressionVariant); }); - - if constexpr(std::is_same_v) { - CollectiveExpressionIO::Move(rCollectiveExpression, rCArrayData, p_list_of_number_of_entities_in_container, - p_list_of_shapes, p_list_of_shape_dimensions, rListOfShapes.size()); - } else { - CollectiveExpressionIO::Read(rCollectiveExpression, rCArrayData, p_list_of_number_of_entities_in_container, - p_list_of_shapes, p_list_of_shape_dimensions, rListOfShapes.size()); - } - - // delete allocated memories - delete[] p_list_of_shapes; - delete[] p_list_of_shape_dimensions; - delete[] p_list_of_number_of_entities_in_container; - - KRATOS_CATCH(""); -} - -void AddContainerSpecificMethods() -{ - -} - -} // namespace Detail - void AddCustomUtilitiesToPython(pybind11::module& m) { namespace py = pybind11; - using SparseSpaceType = UblasSpace; - - using SparseMatrixType = SparseSpaceType::MatrixType; - - using SparseSpaceType = UblasSpace; - - using SparseMatrixType = SparseSpaceType::MatrixType; - using namespace pybind11::literals; py::class_(m, "SymmetryUtility") @@ -217,179 +129,9 @@ void AddCustomUtilitiesToPython(pybind11::module& m) py::arg("neighbour_count_tensor_adaptor")) ; - // Add collective expression to python - pybind11::class_(m, "CollectiveExpression") - .def(pybind11::init<>()) - .def(pybind11::init&>()) - .def("Add", pybind11::overload_cast(&CollectiveExpression::Add)) - .def("Add", pybind11::overload_cast(&CollectiveExpression::Add)) - .def("Clear", &CollectiveExpression::Clear) - .def("Evaluate", [](const CollectiveExpression& rSelf){ - const auto& r_container_expressions = rSelf.GetContainerExpressions(); - if (r_container_expressions.size() > 0) { - bool is_same_item_shape = true; - IndexType number_of_entities = 0; - auto current_shape = std::visit([](auto& pContainerExpression) {return pContainerExpression->GetItemShape();}, r_container_expressions[0]); - - for (const auto& r_container_expression : r_container_expressions) { - is_same_item_shape = is_same_item_shape && std::visit([¤t_shape, &number_of_entities](auto& pContainerExpression){ - number_of_entities += pContainerExpression->GetContainer().size(); - return pContainerExpression->GetItemShape() == current_shape; - }, r_container_expression); - } - - // if all the container expressions does not have the same shape, make the output numpy array scalar. - if (!is_same_item_shape) { - current_shape.clear(); - number_of_entities = rSelf.GetCollectiveFlattenedDataSize(); - } - - auto array = AllocateNumpyArray(number_of_entities, current_shape); - CollectiveExpressionIO::Write(rSelf, array.mutable_data(), array.size()); - return array; - } else { - return AllocateNumpyArray(0, {}); - } - }) - .def("GetCollectiveFlattenedDataSize", &CollectiveExpression::GetCollectiveFlattenedDataSize) - .def("GetContainerExpressions", pybind11::overload_cast<>(&CollectiveExpression::GetContainerExpressions)) - .def("IsCompatibleWith", &CollectiveExpression::IsCompatibleWith) - .def("Clone", &CollectiveExpression::Clone) - .def("__add__", [](const CollectiveExpression& rSelf, const CollectiveExpression& rOther) { return rSelf + rOther; }) - .def("__iadd__", [](CollectiveExpression& rSelf, const CollectiveExpression& rOther) { rSelf = rSelf + rOther; return rSelf; }) - .def("__add__", [](const CollectiveExpression& rSelf, const double Value) { return rSelf + Value; }) - .def("__iadd__", [](CollectiveExpression& rSelf, const double Value) { rSelf = rSelf + Value; return rSelf; }) - .def("__sub__", [](const CollectiveExpression& rSelf, const CollectiveExpression& rOther) { return rSelf - rOther; }) - .def("__isub__", [](CollectiveExpression& rSelf, const CollectiveExpression& rOther) { rSelf = rSelf - rOther; return rSelf; }) - .def("__sub__", [](const CollectiveExpression& rSelf, const double Value) { return rSelf - Value; }) - .def("__isub__", [](CollectiveExpression& rSelf, const double Value) { rSelf = rSelf - Value; return rSelf; }) - .def("__mul__", [](const CollectiveExpression& rSelf, const CollectiveExpression& rOther) { return rSelf * rOther; }) - .def("__imul__", [](CollectiveExpression& rSelf, const CollectiveExpression& rOther) { rSelf = rSelf * rOther; return rSelf; }) - .def("__mul__", [](const CollectiveExpression& rSelf, const double Value) { return rSelf * Value; }) - .def("__imul__", [](CollectiveExpression& rSelf, const double Value) { rSelf = rSelf * Value; return rSelf; }) - .def("__truediv__", [](const CollectiveExpression& rSelf, const CollectiveExpression& rOther) { return rSelf / rOther; }) - .def("__itruediv__", [](CollectiveExpression& rSelf, const CollectiveExpression& rOther) { rSelf = rSelf / rOther; return rSelf; }) - .def("__truediv__", [](const CollectiveExpression& rSelf, const double Value) { return rSelf / Value; }) - .def("__itruediv__", [](CollectiveExpression& rSelf, const double Value) { rSelf = rSelf / Value; return rSelf; }) - .def("__pow__", [](CollectiveExpression& rSelf, const CollectiveExpression& rInput) { CollectiveExpression result; result = ContainerExpressionUtils::Pow(rSelf, rInput); return result; }) - .def("__ipow__", [](CollectiveExpression& rSelf, const CollectiveExpression& rInput) { rSelf = ContainerExpressionUtils::Pow(rSelf, rInput); return rSelf; }) - .def("__pow__", [](CollectiveExpression& rSelf, const double Value) { CollectiveExpression result; result = ContainerExpressionUtils::Pow(rSelf, Value); return result; }) - .def("__ipow__", [](CollectiveExpression& rSelf, const double Value) { rSelf = ContainerExpressionUtils::Pow(rSelf, Value); return rSelf; }) - .def("__neg__", [](CollectiveExpression& rSelf) { return rSelf * -1.0; }) - .def("__str__", &CollectiveExpression::Info) - ; - - - - m.def_submodule("ExpressionUtils") - .def("Collapse", &ContainerExpressionUtils::Collapse, py::arg("collective_expressions")) - .def("Abs", &ContainerExpressionUtils::Abs, py::arg("collective_expressions")) - .def("EntityMin", &ContainerExpressionUtils::EntityMin, py::arg("collective_expressions")) - .def("EntityMax", &ContainerExpressionUtils::EntityMax, py::arg("collective_expressions")) - .def("EntitySum", &ContainerExpressionUtils::EntitySum, py::arg("collective_expressions")) - .def("Sum", &ContainerExpressionUtils::Sum, py::arg("collective_expressions")) - .def("NormInf", &ContainerExpressionUtils::NormInf, py::arg("collective_expressions")) - .def("NormL2", &ContainerExpressionUtils::NormL2, py::arg("collective_expressions")) - .def("Pow", py::overload_cast(&ContainerExpressionUtils::Pow), py::arg("collective_expression"), py::arg("power_coeff")) - .def("Pow", py::overload_cast(&ContainerExpressionUtils::Pow), py::arg("collective_expression"), py::arg("power_coeff_collective_expression")) - .def("Scale", py::overload_cast(&ContainerExpressionUtils::Scale), py::arg("collective_expression"), py::arg("scaling_coeff")) - .def("Scale", py::overload_cast(&ContainerExpressionUtils::Scale), py::arg("collective_expression"), py::arg("scaling_coeff_collective_expression")) - .def("InnerProduct", &ContainerExpressionUtils::InnerProduct, py::arg("collective_expressions_1"), py::arg("collective_expressions_2")) - .def("EntityMaxNormL2", &ContainerExpressionUtils::EntityMaxNormL2, py::arg("container_expression")) - .def("EntityMaxNormL2", &ContainerExpressionUtils::EntityMaxNormL2, py::arg("container_expression")) - .def("EntityMaxNormL2", &ContainerExpressionUtils::EntityMaxNormL2, py::arg("container_expression")) - .def("ProductWithEntityMatrix", py::overload_cast&, const Matrix&, const ContainerExpression&>(&ContainerExpressionUtils::ProductWithEntityMatrix), py::arg("output_container_expression"), py::arg("matrix_with_entity_size"), py::arg("input_container_expression_for_multiplication")) - .def("ProductWithEntityMatrix", py::overload_cast&, const Matrix&, const ContainerExpression&>(&ContainerExpressionUtils::ProductWithEntityMatrix), py::arg("output_container_expression"), py::arg("matrix_with_entity_size"), py::arg("input_container_expression_for_multiplication")) - .def("ProductWithEntityMatrix", py::overload_cast&, const Matrix&, const ContainerExpression&>(&ContainerExpressionUtils::ProductWithEntityMatrix), py::arg("output_container_expression"), py::arg("matrix_with_entity_size"), py::arg("input_container_expression_for_multiplication")) - .def("ProductWithEntityMatrix", py::overload_cast&, const SparseMatrixType&, const ContainerExpression&>(&ContainerExpressionUtils::ProductWithEntityMatrix), py::arg("output_container_expression"), py::arg("matrix_with_entity_size"), py::arg("input_container_expression_for_multiplication")) - .def("ProductWithEntityMatrix", py::overload_cast&, const SparseMatrixType&, const ContainerExpression&>(&ContainerExpressionUtils::ProductWithEntityMatrix), py::arg("output_container_expression"), py::arg("matrix_with_entity_size"), py::arg("input_container_expression_for_multiplication")) - .def("ProductWithEntityMatrix", py::overload_cast&, const SparseMatrixType&, const ContainerExpression&>(&ContainerExpressionUtils::ProductWithEntityMatrix), py::arg("output_container_expression"), py::arg("matrix_with_entity_size"), py::arg("input_container_expression_for_multiplication")) - .def("Transpose", py::overload_cast(&ContainerExpressionUtils::Transpose), py::arg("output_matrix"), py::arg("input_matrix")) - .def("Transpose", py::overload_cast(&ContainerExpressionUtils::Transpose), py::arg("output_matrix"), py::arg("input_matrix")) - .def("ComputeNumberOfNeighbourConditions", &ContainerExpressionUtils::ComputeNumberOfNeighbourEntities, py::arg("output_nodal_container_expression")) - .def("ComputeNumberOfNeighbourElements", &ContainerExpressionUtils::ComputeNumberOfNeighbourEntities, py::arg("output_nodal_container_expression")) - .def("MapContainerVariableToNodalVariable", &ContainerExpressionUtils::MapContainerVariableToNodalVariable, py::arg("output_nodal_container_expression"), py::arg("input_container_expression_to_map"), py::arg("neighbour_container_for_nodes")) - .def("MapContainerVariableToNodalVariable", &ContainerExpressionUtils::MapContainerVariableToNodalVariable, py::arg("output_nodal_container_expression"), py::arg("input_container_expression_to_map"), py::arg("neighbour_container_for_nodes")) - .def("MapNodalVariableToContainerVariable", &ContainerExpressionUtils::MapNodalVariableToContainerVariable, py::arg("output_container_expression"), py::arg("input_nodal_container_expression_to_map")) - .def("MapNodalVariableToContainerVariable", &ContainerExpressionUtils::MapNodalVariableToContainerVariable, py::arg("output_container_expression"), py::arg("input_nodal_container_expression_to_map")) - .def("ComputeNodalVariableProductWithEntityMatrix", &ContainerExpressionUtils::ComputeNodalVariableProductWithEntityMatrix, py::arg("output_nodal_container_expression"), py::arg("input_nodal_values_container_expression"), py::arg("matrix_variable"), py::arg("entities")) - .def("ComputeNodalVariableProductWithEntityMatrix", &ContainerExpressionUtils::ComputeNodalVariableProductWithEntityMatrix, py::arg("output_nodal_container_expression"), py::arg("input_nodal_values_container_expression"), py::arg("matrix_variable"), py::arg("entities")) - .def("ExtractData", &ContainerExpressionUtils::ExtractData, py::arg("input_nodal_expression"), py::arg("model_part_domain_to_extract")) - .def("ExtractData", &ContainerExpressionUtils::ExtractData, py::arg("input_condition_expression"), py::arg("model_part_domain_to_extract")) - .def("ExtractData", &ContainerExpressionUtils::ExtractData, py::arg("input_element_expression"), py::arg("model_part_domain_to_extract")) - ; - - auto collective_expression_io = m.def_submodule("CollectiveExpressionIO"); - py::class_(collective_expression_io, "HistoricalVariable") - .def(py::init(), py::arg("variable")); - py::class_(collective_expression_io, "NonHistoricalVariable") - .def(py::init(), py::arg("variable")); - py::class_(collective_expression_io, "PropertiesVariable") - .def(py::init(), py::arg("variable")); - - collective_expression_io.def("Read", [](CollectiveExpression& rCExpression, const CollectiveExpressionIO::ContainerVariableType& rContainerVariable){ CollectiveExpressionIO::Read(rCExpression, rContainerVariable); }, py::arg("collective_expression"), py::arg("variable_container")); - collective_expression_io.def("Read", [](CollectiveExpression& rCExpression, const std::vector& rContainerVariable){ CollectiveExpressionIO::Read(rCExpression, rContainerVariable); }, py::arg("collective_expression"), py::arg("list_of_variable_containers")); - collective_expression_io.def("Read", [](CollectiveExpression& rCExpression, const py::array_t& rData) { - KRATOS_ERROR_IF(rData.ndim() == 0) << "Passed data is not compatible.\n"; - - // get the shape - std::vector current_shape; - for (int i = 1; i < rData.ndim(); ++i) { - current_shape.push_back(rData.shape(i)); - } - - std::vector> list_of_shapes(rCExpression.GetContainerExpressions().size(), current_shape); - - Detail::CollectiveExpressionFromPythonArray(rCExpression, rData, list_of_shapes, rData.data()); - }, py::arg("collective_expression"), py::arg("numpy_data_array").noconvert()); - collective_expression_io.def("Read", [](CollectiveExpression& rCExpression, const py::array_t& rData, const std::vector>& rListOfShapes) { Detail::CollectiveExpressionFromPythonArray(rCExpression, rData, rListOfShapes, rData.data()); }, py::arg("collective_expression"), py::arg("numpy_data_array").noconvert(), py::arg("list_of_shapes")); - collective_expression_io.def("Move", [](CollectiveExpression& rCExpression, py::array_t& rData) { - KRATOS_ERROR_IF(rData.ndim() == 0) << "Passed data is not compatible.\n"; - - // get the shape - std::vector current_shape; - for (int i = 1; i < rData.ndim(); ++i) { - current_shape.push_back(rData.shape(i)); - } - - std::vector> list_of_shapes(rCExpression.GetContainerExpressions().size(), current_shape); - - Detail::CollectiveExpressionFromPythonArray(rCExpression, rData, list_of_shapes, rData.mutable_data()); - }, py::arg("collective_expression"), py::arg("numpy_data_array").noconvert()); - collective_expression_io.def("Move", [](CollectiveExpression& rCExpression, py::array_t& rData, const std::vector>& rListOfShapes) { Detail::CollectiveExpressionFromPythonArray(rCExpression, rData, rListOfShapes, rData.mutable_data()); }, py::arg("collective_expression"), py::arg("numpy_data_array").noconvert(), py::arg("list_of_shapes")); - collective_expression_io.def("Write", [](CollectiveExpression& rCExpression, const CollectiveExpressionIO::ContainerVariableType& rContainerVariable){ CollectiveExpressionIO::Write(rCExpression, rContainerVariable); }, py::arg("collective_expression"), py::arg("variable_container")); - collective_expression_io.def("Write", [](CollectiveExpression& rCExpression, const std::vector& rContainerVariable){ CollectiveExpressionIO::Write(rCExpression, rContainerVariable); }, py::arg("collective_expression"), py::arg("list_of_variable_containers")); - m.def_submodule("ImplicitFilterUtils") .def("SetBulkRadiusForShapeFiltering", &ImplicitFilterUtils::SetBulkRadiusForShapeFiltering, py::arg("input_model_part")) ; - - - auto properties_variable_expression_io = m.def_submodule("PropertiesVariableExpressionIO"); - properties_variable_expression_io.def("Read", &PropertiesVariableExpressionIO::Read, py::arg("condition_container_expression"), py::arg("variable")); - properties_variable_expression_io.def("Read", &PropertiesVariableExpressionIO::Read, py::arg("element_container_expression"), py::arg("variable")); - properties_variable_expression_io.def("Check", &PropertiesVariableExpressionIO::Check, py::arg("condition_container_expression"), py::arg("variable")); - properties_variable_expression_io.def("Check", &PropertiesVariableExpressionIO::Check, py::arg("element_container_expression"), py::arg("variable")); - properties_variable_expression_io.def("Write", &PropertiesVariableExpressionIO::Write, py::arg("condition_container_expression"), py::arg("variable")); - properties_variable_expression_io.def("Write", &PropertiesVariableExpressionIO::Write, py::arg("element_container_expression"), py::arg("variable")); - - py::class_(properties_variable_expression_io, "Input") - .def(py::init(), - py::arg("model_part"), - py::arg("variable"), - py::arg("data_location")) - ; - - py::class_(properties_variable_expression_io, "Output") - .def(py::init(), - py::arg("model_part"), - py::arg("variable"), - py::arg("data_location")) - ; } } // namespace Python. diff --git a/applications/OptimizationApplication/custom_utilities/collective_expression.cpp b/applications/OptimizationApplication/custom_utilities/collective_expression.cpp deleted file mode 100644 index a5a3ad022b6c..000000000000 --- a/applications/OptimizationApplication/custom_utilities/collective_expression.cpp +++ /dev/null @@ -1,275 +0,0 @@ -// | / | -// ' / __| _` | __| _ \ __| -// . \ | ( | | ( |\__ ` -// _|\_\_| \__,_|\__|\___/ ____/ -// Multi-Physics -// -// License: BSD License -// license: OptimizationApplication/license.txt -// -// Main author: Suneth Warnakulasuriya -// - -// System includes -#include -#include -#include -#include - -// Project includes -#include "expression/arithmetic_operators.h" - -// Application includes - -// Include base h -#include "collective_expression.h" - -namespace Kratos { - -///@name Kratos Classes -///@{ - -CollectiveExpression::CollectiveExpression(const std::vector& rContainerVariableDataHolderPointersList) -{ - for (const auto& p_container_variable_data_holder : rContainerVariableDataHolderPointersList){ - this->Add(p_container_variable_data_holder); - } -} - -CollectiveExpression::CollectiveExpression(const CollectiveExpression& rOther) -{ - for (const auto& p_container_variable_data_holder : rOther.mExpressionPointersList) { - std::visit([&](const auto& v) { - mExpressionPointersList.push_back(v->Clone()); - }, p_container_variable_data_holder); - } -} - -CollectiveExpression& CollectiveExpression::operator=(const CollectiveExpression& rOther) -{ - mExpressionPointersList.clear(); - for (const auto& r_container_variable_data_holder : rOther.mExpressionPointersList) { - std::visit([this](const auto& v) { - mExpressionPointersList.push_back(v); - }, r_container_variable_data_holder); - } - return *this; -} - -CollectiveExpression CollectiveExpression::Clone() const -{ - CollectiveExpression result; - for (const auto& p_container_variable_data_holder : mExpressionPointersList) { - std::visit([&result](const auto& v) { - result.Add(v->Clone()); - }, p_container_variable_data_holder); - } - return result; -} - -void CollectiveExpression::Add(const CollectiveExpressionType& pVariableDataHolder) -{ - std::visit([&](const auto& v) { - mExpressionPointersList.push_back(v); - }, pVariableDataHolder); -} - -void CollectiveExpression::Add(const CollectiveExpression& rCollectiveVariableDataHolder) -{ - for (const auto& p_container_variable_data_holder : rCollectiveVariableDataHolder.mExpressionPointersList) { - std::visit([&](const auto& v) { - mExpressionPointersList.push_back(v); - }, p_container_variable_data_holder); - } -} - -void CollectiveExpression::Clear() -{ - mExpressionPointersList.clear(); -} - -IndexType CollectiveExpression::GetCollectiveFlattenedDataSize() const -{ - IndexType size = 0; - for (const auto& p_container_variable_data_holder : mExpressionPointersList) { - std::visit([&size](const auto& v) { - size += v->GetContainer().size() * v->GetItemComponentCount(); - }, p_container_variable_data_holder); - } - - return size; -} - -std::vector CollectiveExpression::GetContainerExpressions() -{ - return mExpressionPointersList; -} - -std::vector CollectiveExpression::GetContainerExpressions() const -{ - return mExpressionPointersList; -} - -bool CollectiveExpression::IsCompatibleWith(const CollectiveExpression& rOther) const -{ - if (mExpressionPointersList.size() != rOther.mExpressionPointersList.size()) { - return false; - } - - bool is_compatible = true; - - for (IndexType i = 0; i < mExpressionPointersList.size(); ++i) { - const auto& r_other_expression = rOther.mExpressionPointersList[i]; - std::visit([&r_other_expression, &is_compatible](const auto& v) { - using v_type = std::decay_t; - auto* ptr = std::get_if(&r_other_expression); - is_compatible = is_compatible && (ptr != nullptr) && ((*ptr)->GetContainer().size() == v->GetContainer().size()); - }, mExpressionPointersList[i]); - } - - return is_compatible; -} - -std::string CollectiveExpression::Info() const -{ - std::stringstream msg; - - msg << "CollectiveExpression contains following data holders:\n"; - - for (const auto& p_container_variable_data_holder : mExpressionPointersList) { - std::visit([&msg](const auto& v) { msg << "\t" << *v; }, p_container_variable_data_holder); - } - - return msg.str(); -} - -#define KRATOS_DEFINE_BINARY_COLLECTIVE_EXPRESSION_OPERATOR(OPERATOR_NAME) \ - CollectiveExpression OPERATOR_NAME(const CollectiveExpression& rLeft, const double Right) \ - { \ - KRATOS_TRY \ - \ - auto result = rLeft; \ - auto r_list_of_container_expressions = result.GetContainerExpressions(); \ - for (IndexType i = 0; i < r_list_of_container_expressions.size(); ++i) { \ - std::visit( \ - [Right](auto& pResult) { \ - pResult->SetExpression(OPERATOR_NAME(pResult->pGetExpression(), Right)); \ - }, \ - r_list_of_container_expressions[i]); \ - } \ - return result; \ - \ - KRATOS_CATCH("") \ - } \ - \ - CollectiveExpression OPERATOR_NAME(const double Left, const CollectiveExpression& rRight) \ - { \ - KRATOS_TRY \ - \ - auto result = rRight; \ - auto r_list_of_container_expressions = result.GetContainerExpressions(); \ - for (IndexType i = 0; i < r_list_of_container_expressions.size(); ++i) { \ - std::visit( \ - [Left](auto& pResult) { \ - pResult->SetExpression(OPERATOR_NAME(pResult->pGetExpression(), Left)); \ - }, \ - r_list_of_container_expressions[i]); \ - } \ - return result; \ - \ - KRATOS_CATCH("") \ - } \ - \ - CollectiveExpression OPERATOR_NAME(const CollectiveExpression& rLeft, \ - const CollectiveExpression& rRight) \ - { \ - KRATOS_TRY \ - \ - KRATOS_ERROR_IF_NOT(rLeft.IsCompatibleWith(rRight)) \ - << "Unsupported collective variable data holders provided for " \ - "\"" \ - << #OPERATOR_NAME << "\"." \ - << "\nLeft operand : " << rLeft << "\nRight operand: " << rRight \ - << std::endl; \ - \ - auto result = rLeft; \ - auto r_list_of_container_expressions = result.GetContainerExpressions(); \ - const auto& r_right_container_expressions = rRight.GetContainerExpressions(); \ - for (IndexType i = 0; i < r_list_of_container_expressions.size(); ++i) { \ - std::visit( \ - [&r_right_container_expressions, i](auto& pResult) { \ - auto p_right = std::get>( \ - r_right_container_expressions[i]); \ - pResult->SetExpression(OPERATOR_NAME( \ - pResult->pGetExpression(), p_right->pGetExpression())); \ - }, \ - r_list_of_container_expressions[i]); \ - } \ - return result; \ - \ - KRATOS_CATCH(""); \ - } - -#define KRATOS_DEFINE_UNARY_COLLECTIVE_EXPRESSION_OPERATOR(OPERATOR_NAME, EXPRESSION_OPERATOR_NAME) \ - CollectiveExpression& CollectiveExpression::OPERATOR_NAME(const double Value) \ - { \ - KRATOS_TRY \ - \ - for (auto& p_expression : mExpressionPointersList) { \ - std::visit( \ - [Value](auto& pContainerExpression) { \ - pContainerExpression->SetExpression(EXPRESSION_OPERATOR_NAME( \ - pContainerExpression->pGetExpression(), Value)); \ - }, \ - p_expression); \ - } \ - \ - return *this; \ - \ - KRATOS_CATCH(""); \ - } \ - \ - CollectiveExpression& CollectiveExpression::OPERATOR_NAME(const CollectiveExpression& rOther) \ - { \ - KRATOS_TRY \ - \ - KRATOS_ERROR_IF_NOT(IsCompatibleWith(rOther)) \ - << "Unsupported collective variable data holders provided for " \ - "\"" \ - << #OPERATOR_NAME << "\"." \ - << "\nLeft operand : " << *this << "\nRight operand: " << rOther \ - << std::endl; \ - \ - const auto& r_other_epxressions_list = rOther.GetContainerExpressions(); \ - for (IndexType i = 0; i < mExpressionPointersList.size(); ++i) { \ - std::visit( \ - [&r_other_epxressions_list, i](auto& pContainerExpression) { \ - auto p_other = \ - std::get>( \ - r_other_epxressions_list[i]); \ - \ - pContainerExpression->SetExpression(EXPRESSION_OPERATOR_NAME( \ - pContainerExpression->pGetExpression(), p_other->pGetExpression())); \ - }, \ - mExpressionPointersList[i]); \ - } \ - \ - return *this; \ - \ - KRATOS_CATCH(""); \ - } - -KRATOS_DEFINE_BINARY_COLLECTIVE_EXPRESSION_OPERATOR(operator+) -KRATOS_DEFINE_BINARY_COLLECTIVE_EXPRESSION_OPERATOR(operator-) -KRATOS_DEFINE_BINARY_COLLECTIVE_EXPRESSION_OPERATOR(operator*) -KRATOS_DEFINE_BINARY_COLLECTIVE_EXPRESSION_OPERATOR(operator/) - -KRATOS_DEFINE_UNARY_COLLECTIVE_EXPRESSION_OPERATOR(operator+=, operator+) -KRATOS_DEFINE_UNARY_COLLECTIVE_EXPRESSION_OPERATOR(operator-=, operator-) -KRATOS_DEFINE_UNARY_COLLECTIVE_EXPRESSION_OPERATOR(operator*=, operator*) -KRATOS_DEFINE_UNARY_COLLECTIVE_EXPRESSION_OPERATOR(operator/=, operator/) - -#undef KRATOS_DEFINE_BINARY_COLLECTIVE_EXPRESSION_OPERATOR -#undef KRATOS_DEFINE_UNARY_COLLECTIVE_EXPRESSION_OPERATOR - -} // namespace Kratos \ No newline at end of file diff --git a/applications/OptimizationApplication/custom_utilities/collective_expression.h b/applications/OptimizationApplication/custom_utilities/collective_expression.h deleted file mode 100644 index 16368b92f493..000000000000 --- a/applications/OptimizationApplication/custom_utilities/collective_expression.h +++ /dev/null @@ -1,184 +0,0 @@ -// | / | -// ' / __| _` | __| _ \ __| -// . \ | ( | | ( |\__ ` -// _|\_\_| \__,_|\__|\___/ ____/ -// Multi-Physics -// -// License: BSD License -// license: OptimizationApplication/license.txt -// -// Main author: Suneth Warnakulasuriya -// - -#pragma once - -// System includes -#include -#include -#include - -// Project includes -#include "expression/container_expression.h" -#include "expression/traits.h" -#include "includes/define.h" -#include "includes/model_part.h" - -// Application includes -#include "collective_expression_arithmetic_operators.h" - -namespace Kratos { - -///@name Kratos Classes -///@{ -/** - * @brief Construct a new CollectiveExpression instance - * @details This constructs a CollectiveExpression instance which can hold list of ContainerExpresions of different types. - * The list within the instance can be treated as a single value, therefore all the binary operations present in the ContainerExpressions - * are also available with this container. This uses std::variant to store different types of containers. Since these containers memory footprint - * is the same, the memory footprint of the std::variant will be almost equal to the memory footprint of a single container for all the container types. - * - */ -class KRATOS_API(OPTIMIZATION_APPLICATION) CollectiveExpression { -public: - ///@name Type definitions - ///@{ - - using IndexType = std::size_t; - - using CollectiveExpressionType = std::variant< - ContainerExpression::Pointer, - ContainerExpression::Pointer, - ContainerExpression::Pointer>; - - KRATOS_CLASS_POINTER_DEFINITION(CollectiveExpression); - - ///@} - ///@name Life cycle - ///#{ - - // Default constructor - CollectiveExpression() noexcept = default; - - - /** - * @brief Construct a list of container expressions - * - * @param rExpressionPointersList List of container expressions - */ - CollectiveExpression(const std::vector& rExpressionPointersList); - - // Copy constructor - CollectiveExpression(const CollectiveExpression& rOther); - - /// Assignment operator - CollectiveExpression& operator=(const CollectiveExpression& rOther); - - // destructor - ~CollectiveExpression() = default; - - ///@} - ///@name Public operations - ///@{ - - /** - * @brief Clones this collective expressions by cloning all the ContainerExpressions in the instance. - * - * This clones current instance of CollectiveExpression by cloning all the ContainerExpressions. Cloning - * a single ContainerExpression is a light weight operation, hence this operation also a light weight operation. - * - * @return CollectiveExpression Cloned collective expressions which has all the clones of ContainerExpressions. - */ - CollectiveExpression Clone() const; - - /** - * @brief Add a ContainerExpression to the current instance. - * - * @param pExpression The ContainerExpression to be added. - */ - void Add(const CollectiveExpressionType& pExpression); - - /** - * @brief Add a CollectiveExpression to the current instance. - * - * This method appends the current instance's list of ContainerExpressions with the new ContainerExpressions - * in @ref rCollectiveExpression. - * - * @param rCollectiveExpression The CollectiveExpression to be appended to the current CollectiveExpression. - */ - void Add(const CollectiveExpression& rCollectiveExpression); - - /** - * @brief Clear list of all the ContainerExpressions. - * - * This does not destroy the corresponding ContainerExpression (uses SmartPointers). This removes - * all the ContainerExpression objects from the current list. - * - */ - void Clear(); - - /** - * @brief Get the Collective Flattened Data Size. - * - * This method returns the total number of double values present in all the ContainerExpressions. - * - * @return IndexType Total number of double values present in all the ContainerExpressions. - */ - IndexType GetCollectiveFlattenedDataSize() const; - - std::vector GetContainerExpressions(); - - std::vector GetContainerExpressions() const; - - bool IsCompatibleWith(const CollectiveExpression& rOther) const; - - ///@} - ///@name Public operators - ///@{ - - CollectiveExpression& operator+=(const CollectiveExpression& rOther); - - CollectiveExpression& operator+=(const double Value); - - CollectiveExpression& operator-=(const CollectiveExpression& rOther); - - CollectiveExpression& operator-=(const double Value); - - CollectiveExpression& operator*=(const CollectiveExpression& rOther); - - CollectiveExpression& operator*=(const double Value); - - CollectiveExpression& operator/=(const CollectiveExpression& rOther); - - CollectiveExpression& operator/=(const double Value); - - ///@} - ///@name Input and output - ///@{ - - std::string Info() const; - - ///@} -private: - ///@name Private variables - ///@{ - - std::vector mExpressionPointersList; - - ///@} -}; - -///@} -///@name Input and output -///@{ - -/// output stream function -inline std::ostream& operator<<( - std::ostream& rOStream, - const CollectiveExpression& rThis) -{ - return rOStream << rThis.Info(); -} - -///@} - -} // namespace Kratos \ No newline at end of file diff --git a/applications/OptimizationApplication/custom_utilities/collective_expression_arithmetic_operators.h b/applications/OptimizationApplication/custom_utilities/collective_expression_arithmetic_operators.h deleted file mode 100644 index 05a2ca710cb4..000000000000 --- a/applications/OptimizationApplication/custom_utilities/collective_expression_arithmetic_operators.h +++ /dev/null @@ -1,53 +0,0 @@ -// | / | -// ' / __| _` | __| _ \ __| -// . \ | ( | | ( |\__ ` -// _|\_\_| \__,_|\__|\___/ ____/ -// Multi-Physics -// -// License: BSD License -// Kratos default license: kratos/license.txt -// -// Main authors: Suneth Warnakulasuriya -// - -#pragma once - -// Project includes -#include "includes/define.h" - -namespace Kratos { - - -/// @name Arithmetic Operators -/// @{ - -class CollectiveExpression; - -KRATOS_API(OPTIMIZATION_APPLICATION) CollectiveExpression operator+(const CollectiveExpression& rLeft, const double Right); - -KRATOS_API(OPTIMIZATION_APPLICATION) CollectiveExpression operator+(const double Left, const CollectiveExpression& rRight); - -KRATOS_API(OPTIMIZATION_APPLICATION) CollectiveExpression operator+(const CollectiveExpression& rLeft, const CollectiveExpression& rRight); - -KRATOS_API(OPTIMIZATION_APPLICATION) CollectiveExpression operator-(const CollectiveExpression& rLeft, const double Right); - -KRATOS_API(OPTIMIZATION_APPLICATION) CollectiveExpression operator-(const double Left, const CollectiveExpression& rRight); - -KRATOS_API(OPTIMIZATION_APPLICATION) CollectiveExpression operator-(const CollectiveExpression& rLeft, const CollectiveExpression& rRight); - -KRATOS_API(OPTIMIZATION_APPLICATION) CollectiveExpression operator*(const CollectiveExpression& rLeft, const double Right); - -KRATOS_API(OPTIMIZATION_APPLICATION) CollectiveExpression operator*(const double Left, const CollectiveExpression& rRight); - -KRATOS_API(OPTIMIZATION_APPLICATION) CollectiveExpression operator*(const CollectiveExpression& rLeft, const CollectiveExpression& rRight); - -KRATOS_API(OPTIMIZATION_APPLICATION) CollectiveExpression operator/(const CollectiveExpression& rLeft, const double Right); - -KRATOS_API(OPTIMIZATION_APPLICATION) CollectiveExpression operator/(const double Left, const CollectiveExpression& rRight); - -KRATOS_API(OPTIMIZATION_APPLICATION) CollectiveExpression operator/(const CollectiveExpression& rLeft, const CollectiveExpression& rRight); - -/// @} - - -} // namespace Kratos diff --git a/applications/OptimizationApplication/custom_utilities/collective_expression_io.cpp b/applications/OptimizationApplication/custom_utilities/collective_expression_io.cpp deleted file mode 100644 index 217f57b1dcda..000000000000 --- a/applications/OptimizationApplication/custom_utilities/collective_expression_io.cpp +++ /dev/null @@ -1,235 +0,0 @@ -// | / | -// ' / __| _` | __| _ \ __| -// . \ | ( | | ( |\__ ` -// _|\_\_| \__,_|\__|\___/ ____/ -// Multi-Physics -// -// License: BSD License -// Kratos default license: kratos/license.txt -// -// Main authors: Suneth Warnakulasuriya -// - -// System includes - -// Project includes -#include "includes/define.h" -#include "includes/model_part.h" -#include "expression/c_array_expression_io.h" -#include "expression/variable_expression_io.h" - -// Application includes -#include "properties_variable_expression_io.h" - -// Include base h -#include "collective_expression_io.h" - -namespace Kratos { - -template -void CollectiveExpressionIO::Read( - CollectiveExpression& rCollectiveExpression, - TRawDataType const* pBegin, - int const* NumberOfEntities, - int const** pListShapeBegin, - int const* ShapeSizes, - const int NumberOfContainers) -{ - KRATOS_TRY - - KRATOS_ERROR_IF_NOT(NumberOfContainers > 0 && static_cast(NumberOfContainers) == rCollectiveExpression.GetContainerExpressions().size()) - << "Number of containers mismatch. [ Input number of containers = " << NumberOfContainers - << ", CollectiveExpression number of containers = " - << rCollectiveExpression.GetContainerExpressions().size() << " ].\n"; - - for (auto& p_container_variable_data_holder : rCollectiveExpression.GetContainerExpressions()) { - std::visit([&pBegin, &pListShapeBegin, &ShapeSizes, &NumberOfEntities](auto& v) { - CArrayExpressionIO::Read(*v, pBegin, *NumberOfEntities, *pListShapeBegin, *ShapeSizes); - - // now offset everything - pBegin += v->GetContainer().size() * v->GetItemComponentCount(); - ++pListShapeBegin; - ++ShapeSizes; - ++NumberOfEntities; - }, p_container_variable_data_holder); - } - - KRATOS_CATCH(""); -} - -template -void CollectiveExpressionIO::Move( - CollectiveExpression& rCollectiveExpression, - TRawDataType* pBegin, - int const* NumberOfEntities, - int const** pListShapeBegin, - int const* ShapeSizes, - const int NumberOfContainers) -{ - KRATOS_TRY - - KRATOS_ERROR_IF_NOT(NumberOfContainers > 0 && static_cast(NumberOfContainers) == rCollectiveExpression.GetContainerExpressions().size()) - << "Number of containers mismatch. [ Input number of containers = " << NumberOfContainers - << ", CollectiveExpression number of containers = " - << rCollectiveExpression.GetContainerExpressions().size() << " ].\n"; - - for (auto& p_container_variable_data_holder : rCollectiveExpression.GetContainerExpressions()) { - std::visit([&pBegin, &pListShapeBegin, &ShapeSizes, &NumberOfEntities](const auto& v) { - CArrayExpressionIO::Move(*v, pBegin, *NumberOfEntities, *pListShapeBegin, *ShapeSizes); - - // now offset everything - pBegin += v->GetContainer().size() * v->GetItemComponentCount(); - ++pListShapeBegin; - ++ShapeSizes; - ++NumberOfEntities; - }, p_container_variable_data_holder); - } - - KRATOS_CATCH(""); -} - -template -void CollectiveExpressionIO::Write( - const CollectiveExpression& rCollectiveExpression, - TRawDataType* pBegin, - const int Size) -{ - KRATOS_ERROR_IF_NOT(Size > 0 && static_cast(Size) == rCollectiveExpression.GetCollectiveFlattenedDataSize()) - << "The size of the double vector does not match with the required " - "collective expression size. [ " - "Size = " - << Size << ", collective expression data size = " - << rCollectiveExpression.GetCollectiveFlattenedDataSize() << " ].\n"; - - for (const auto& p_container_variable_data_holder : rCollectiveExpression.GetContainerExpressions()) { - std::visit([&pBegin](const auto& v) { - // get the shape of the container expression. - const auto& r_shape = v->GetItemShape(); - - // transform unsigned Index type shape to signed int shape. - std::vector shape(r_shape.size()); - std::transform(r_shape.begin(), r_shape.end(), shape.begin(), [](const IndexType Value) -> int { return Value; }); - - // get the number of entities in the container. - const auto number_of_entities = v->GetContainer().size(); - - // evaluate the expression and put the result in a continuous array starting with pBegin. - CArrayExpressionIO::Write(*v, pBegin, number_of_entities * v->GetItemComponentCount()); - - // increase the offset to place the evaluated values of the next container expression correctly. - pBegin += number_of_entities * v->GetItemComponentCount(); - }, p_container_variable_data_holder); - } -} - -void CollectiveExpressionIO::Read( - CollectiveExpression& rCollectiveExpression, - const std::vector& rContainerVariables) -{ - const auto& r_container_expressions = rCollectiveExpression.GetContainerExpressions(); - - KRATOS_ERROR_IF_NOT(r_container_expressions.size() == rContainerVariables.size()) - << "Container expressions size and variables size mismatch. [ number of container expressions = " - << r_container_expressions.size() << ", number of variable container types = " << rContainerVariables.size() << " ].\n"; - - for (IndexType i = 0; i < r_container_expressions.size(); ++i) { - std::visit([](auto& pContainer, auto& pContainerVariable) { - using container_expression_type = std::decay_t; - using container_variable_type = std::decay_t; - - if constexpr(std::is_same_v> || - std::is_same_v> || - std::is_same_v>) { - if constexpr(std::is_same_v) { - VariableExpressionIO::Read(*pContainer, pContainerVariable->mVariable, true); - } else if constexpr(std::is_same_v) { - VariableExpressionIO::Read(*pContainer, pContainerVariable->mVariable, false); - } else { - KRATOS_ERROR - << "Nodal expressions only supports HistoricalVariable " - "and NonHistoricalVariable container types.\n"; - } - } else { - if constexpr(std::is_same_v) { - VariableExpressionIO::Read(*pContainer, pContainerVariable->mVariable); - } else if constexpr(std::is_same_v) { - PropertiesVariableExpressionIO::Read(*pContainer, pContainerVariable->mVariable); - } else { - KRATOS_ERROR << "Element/Condition expressions only " - "supports NonHistoricalVariable and " - "PropertiesVariable container types.\n"; - } - } - }, r_container_expressions[i], rContainerVariables[i]); - } -} - -void CollectiveExpressionIO::Read( - CollectiveExpression& rCollectiveExpression, - const ContainerVariableType& rContainerVariable) -{ - std::vector variables(rCollectiveExpression.GetContainerExpressions().size(), rContainerVariable); - Read(rCollectiveExpression, variables); -} - -void CollectiveExpressionIO::Write( - const CollectiveExpression& rCollectiveExpression, - const std::vector& rContainerVariables) -{ - const auto& r_container_expressions = rCollectiveExpression.GetContainerExpressions(); - - KRATOS_ERROR_IF_NOT(r_container_expressions.size() == rContainerVariables.size()) - << "Container expressions size and variables size mismatch. [ number of container expressions = " - << r_container_expressions.size() << ", number of variable container types = " << rContainerVariables.size() << " ].\n"; - - for (IndexType i = 0; i < r_container_expressions.size(); ++i) { - std::visit([](auto& pContainer, auto& pContainerVariable) { - using container_expression_type = std::decay_t; - using container_variable_type = std::decay_t; - - if constexpr(std::is_same_v> || - std::is_same_v> || - std::is_same_v>) { - if constexpr(std::is_same_v) { - VariableExpressionIO::Write(*pContainer, pContainerVariable->mVariable, true); - } else if constexpr(std::is_same_v) { - VariableExpressionIO::Write(*pContainer, pContainerVariable->mVariable, false); - } else { - KRATOS_ERROR - << "Nodal expressions only supports HistoricalVariable " - "and NonHistoricalVariable container types.\n"; - } - } else { - if constexpr(std::is_same_v) { - VariableExpressionIO::Write(*pContainer, pContainerVariable->mVariable); - } else if constexpr(std::is_same_v) { - PropertiesVariableExpressionIO::Write(*pContainer, pContainerVariable->mVariable); - } else { - KRATOS_ERROR << "Element/Condition expressions only " - "supports NonHistoricalVariable and " - "PropertiesVariable container types.\n"; - } - } - }, r_container_expressions[i], rContainerVariables[i]); - } -} - -void CollectiveExpressionIO::Write( - const CollectiveExpression& rCollectiveExpression, - const ContainerVariableType& rContainerVariable) -{ - std::vector variables(rCollectiveExpression.GetContainerExpressions().size(), rContainerVariable); - Write(rCollectiveExpression, variables); -} - -// template instantiations -template KRATOS_API(OPTIMIZATION_APPLICATION) void CollectiveExpressionIO::Read(CollectiveExpression&, int const*, int const*, int const**, int const*, const int); -template KRATOS_API(OPTIMIZATION_APPLICATION) void CollectiveExpressionIO::Read(CollectiveExpression&, double const*, int const*, int const**, int const*, const int); - -template KRATOS_API(OPTIMIZATION_APPLICATION) void CollectiveExpressionIO::Move(CollectiveExpression&, int*, int const*, int const**, int const*, const int); -template KRATOS_API(OPTIMIZATION_APPLICATION) void CollectiveExpressionIO::Move(CollectiveExpression&, double*, int const*, int const**, int const*, const int); - -template KRATOS_API(OPTIMIZATION_APPLICATION) void CollectiveExpressionIO::Write(const CollectiveExpression&, int*, const int); -template KRATOS_API(OPTIMIZATION_APPLICATION) void CollectiveExpressionIO::Write(const CollectiveExpression&, double*, const int); - -} // namespace Kratos diff --git a/applications/OptimizationApplication/custom_utilities/collective_expression_io.h b/applications/OptimizationApplication/custom_utilities/collective_expression_io.h deleted file mode 100644 index 50c3b44d6b14..000000000000 --- a/applications/OptimizationApplication/custom_utilities/collective_expression_io.h +++ /dev/null @@ -1,155 +0,0 @@ -// | / | -// ' / __| _` | __| _ \ __| -// . \ | ( | | ( |\__ ` -// _|\_\_| \__,_|\__|\___/ ____/ -// Multi-Physics -// -// License: BSD License -// Kratos default license: kratos/license.txt -// -// Main authors: Suneth Warnakulasuriya -// - -#pragma once - -// System includes -#include - -// Project includes -#include "includes/define.h" - -// Application includes -#include "collective_expression.h" - -namespace Kratos { - -class KRATOS_API(OPTIMIZATION_APPLICATION) CollectiveExpressionIO -{ -public: - ///@name Type definitions - ///@{ - - using VariableType = std::variant< - const Variable*, - const Variable*, - const Variable>*, - const Variable>*, - const Variable>*, - const Variable>*, - const Variable*, - const Variable*>; - - ///@} - ///@name Public classes - ///@{ - - class HistoricalVariable - { - public: - ///@name Life cycle - ///@{ - - KRATOS_CLASS_POINTER_DEFINITION(HistoricalVariable); - - HistoricalVariable(const VariableType& rVariable): mVariable(rVariable) {} - - ///@} - ///@name Public member variables - ///@{ - - const VariableType mVariable; - - ///@} - }; - - class NonHistoricalVariable - { - public: - ///@name Life cycle - ///@{ - - KRATOS_CLASS_POINTER_DEFINITION(NonHistoricalVariable); - - NonHistoricalVariable(const VariableType& rVariable): mVariable(rVariable) {} - - ///@} - ///@name Public member variables - ///@{ - - const VariableType mVariable; - - ///@} - }; - - class PropertiesVariable - { - public: - ///@name Life cycle - ///@{ - - KRATOS_CLASS_POINTER_DEFINITION(PropertiesVariable); - - PropertiesVariable(const VariableType& rVariable): mVariable(rVariable) {} - - ///@} - ///@name Public member variables - ///@{ - - const VariableType mVariable; - - ///@} - }; - - using ContainerVariableType = std::variant< - HistoricalVariable::Pointer, - NonHistoricalVariable::Pointer, - PropertiesVariable::Pointer>; - - ///@} - ///@name Public static operations - ///@{ - - template - static void Read( - CollectiveExpression& rCollectiveExpression, - TRawDataType const* pBegin, - int const* NumberOfEntities, - int const** pListShapeBegin, - int const* ShapeSizes, - const int NumberOfContainers); - - template - static void Move( - CollectiveExpression& rCollectiveExpression, - TRawDataType* pBegin, - int const* NumberOfEntities, - int const** pListShapeBegin, - int const* ShapeSizes, - const int NumberOfContainers); - - template - static void Write( - const CollectiveExpression& rCollectiveExpression, - TRawDataType* pBegin, - const int Size); - - static void Read( - CollectiveExpression& rCollectiveExpression, - const ContainerVariableType& rContainerVariable); - - static void Read( - CollectiveExpression& rCollectiveExpression, - const std::vector& rContainerVariables); - - static void Write( - const CollectiveExpression& rCollectiveExpression, - const ContainerVariableType& rContainerVariable); - - static void Write( - const CollectiveExpression& rCollectiveExpression, - const std::vector& rContainerVariables); - - ///@} -}; - -} // namespace Kratos diff --git a/applications/OptimizationApplication/custom_utilities/container_expression_utils.cpp b/applications/OptimizationApplication/custom_utilities/container_expression_utils.cpp deleted file mode 100644 index 8c182a8a8d4e..000000000000 --- a/applications/OptimizationApplication/custom_utilities/container_expression_utils.cpp +++ /dev/null @@ -1,625 +0,0 @@ -// | / | -// ' / __| _` | __| _ \ __| -// . \ | ( | | ( |\__ ` -// _|\_\_| \__,_|\__|\___/ ____/ -// Multi-Physics -// -// License: BSD License -// license: OptimizationApplication/license.txt -// -// Main author: Suneth Warnakulasuriya -// - -// System includes -#include -#include -#include -#include - -// Project includes -#include "expression/variable_expression_data_io.h" -#include "expression/container_data_io.h" -#include "expression/container_expression.h" -#include "expression/variable_expression_io.h" -#include "expression/literal_expression_input.h" -#include "includes/define.h" -#include "includes/model_part.h" -#include "utilities/atomic_utilities.h" -#include "utilities/parallel_utilities.h" -#include "utilities/reduction_utilities.h" -#include "utilities/variable_utils.h" -#include "utilities/atomic_utilities.h" -#include "utilities/model_part_utils.h" - -// Application includes -#include "optimization_application_variables.h" - -// Include base h -#include "container_expression_utils.h" - -namespace Kratos -{ - -namespace ContainerVariableDataHolderUtilsHelper -{ -using VariableVariantType = std::variant*, const Variable>*>; -using VariablePairVariantType = std::variant< - std::pair*, const Variable*>, - std::pair>*, const Variable>*>>; - -VariableVariantType GetTemporaryVariable(const std::vector& rShape) -{ - if (rShape.size() == 0) { - return &TEMPORARY_SCALAR_VARIABLE_1; - } else if (rShape == std::vector{3}) { - return &TEMPORARY_ARRAY3_VARIABLE_1; - } else { - KRATOS_ERROR << "Unsupported data shape = " - << rShape << ". Only scalar and array3 data shapes are supported for temporary variable retrieval.\n"; - } - return &TEMPORARY_SCALAR_VARIABLE_1; -} - -VariablePairVariantType GetTemporaryVariable1And2(const std::vector& rShape) -{ - if (rShape.size() == 0) { - return std::make_pair(&TEMPORARY_SCALAR_VARIABLE_1, &TEMPORARY_SCALAR_VARIABLE_2); - } else if (rShape == std::vector{3}) { - return std::make_pair(&TEMPORARY_ARRAY3_VARIABLE_2, &TEMPORARY_ARRAY3_VARIABLE_2); - } else { - KRATOS_ERROR << "Unsupported data shape = " - << rShape << ". Only scalar and array3 data shapes are supported for temporary variable retrieval.\n"; - } - return std::make_pair(&TEMPORARY_SCALAR_VARIABLE_1, &TEMPORARY_SCALAR_VARIABLE_2); -} - -template, - std::is_same, - std::is_same> - , bool> = true> -inline void GenericAtomicAdd( - TDataType1& rOutput, - const TDataType2& rInput) -{ - if constexpr(std::is_arithmetic_v) { - AtomicAdd(rOutput, rInput); - } else if constexpr(std::is_same_v) { - AtomicAddVector(rOutput, rInput); - } else if constexpr(std::is_same_v) { - AtomicAddMatrix(rOutput, rInput); - } else { - // This will be never reached. But having this - // gives some peace of mind. - static_assert(!std::is_same_v, "Unsupported atomic add."); - } -} - -template -inline void GenericAtomicAdd( - array_1d& rOutput, - const TDataType2& rInput) -{ - AtomicAdd(rOutput, rInput); -} - -template -typename VariableExpressionDataIO::Pointer GetVariableExpressionDataIO( - const Variable& rVaraible, - const std::vector& rShape) -{ - return VariableExpressionDataIO::Create(rShape); -} - -void ComputeMatrixExpressionProduct( - LiteralFlatExpression& rOutputExpression, - const Matrix& rMatrix, - const LiteralFlatExpression& rInputExpression, - const IndexType NumberOfEntities, - const IndexType ExpressionLocalSize) -{ - KRATOS_TRY - - const IndexType row_local_size = rMatrix.size1() / NumberOfEntities; - const IndexType col_local_size = rMatrix.size2() / NumberOfEntities; - - for (IndexType i = 0; i < NumberOfEntities; ++i) { - const IndexType matrix_row_begin = i * row_local_size; - const IndexType output_data_begin = i * ExpressionLocalSize; - - IndexType output_component_index; - - // fill the output expression with the values from the matrix vector multiplication. - for (output_component_index = 0; output_component_index < row_local_size; ++output_component_index) { - for (IndexType j = 0; j < NumberOfEntities; ++j) { - const IndexType matrix_col_begin = j * col_local_size; - const IndexType input_data_begin = j * ExpressionLocalSize; - - for (IndexType input_component_index = 0; input_component_index < col_local_size; ++input_component_index) { - rOutputExpression.SetData( - output_data_begin, output_component_index, - rMatrix(matrix_row_begin + output_component_index, - matrix_col_begin + input_component_index) * - rInputExpression.Evaluate(j, input_data_begin, input_component_index)); - } - } - } - - // set the rest of the components in 2D to zero because, the expression - // local size is 3 even for 2D in array3 case. - for (; output_component_index < ExpressionLocalSize; ++output_component_index) { - rOutputExpression.SetData(output_data_begin, output_component_index, 0.0); - } - } - - KRATOS_CATCH(""); -} -} // namespace ContainerVariableDataHolderUtilsHelper - -template -double ContainerExpressionUtils::EntityMaxNormL2(const ContainerExpression& rContainer) -{ - if (rContainer.GetItemComponentCount() == 0) { - return 0.0; - } - - const auto& r_expression = rContainer.GetExpression(); - const IndexType local_size = rContainer.GetItemComponentCount(); - const IndexType number_of_entities = rContainer.GetContainer().size(); - - return std::sqrt(rContainer.GetModelPart().GetCommunicator().GetDataCommunicator().MaxAll(IndexPartition(number_of_entities).for_each>([&r_expression, local_size](const IndexType EntityIndex) { - const IndexType local_data_begin_index = EntityIndex * local_size; - double value = 0.0; - for (IndexType i = 0; i < local_size; ++i) { - value += std::pow(r_expression.Evaluate(EntityIndex, local_data_begin_index, i), 2); - } - return value; - }))); -} - -double ContainerExpressionUtils::InnerProduct( - const CollectiveExpression& rContainer1, - const CollectiveExpression& rContainer2) -{ - KRATOS_ERROR_IF_NOT(rContainer1.IsCompatibleWith(rContainer2)) - << "Unsupported collective variable data holders provided for \"+\" operation." - << "\nLeft operand : " << rContainer1 << "\nRight operand: " << rContainer2 << std::endl; - - double inner_product_value = 0.0; - for (IndexType i = 0; i < rContainer1.GetContainerExpressions().size(); ++i) { - const auto v_2 = rContainer2.GetContainerExpressions()[i]; - std::visit([&inner_product_value, &v_2](const auto& v_1) { - using v_type = std::decay_t; - inner_product_value += ExpressionUtils::InnerProduct(*v_1, *std::get(v_2)); - }, rContainer1.GetContainerExpressions()[i]); - } - return inner_product_value; -} - -template -void ContainerExpressionUtils::ProductWithEntityMatrix( - ContainerExpression& rOutput, - const SparseMatrixType& rMatrix, - const ContainerExpression& rInput) -{ - KRATOS_ERROR_IF(rInput.GetModelPart().IsDistributed() || - rOutput.GetModelPart().IsDistributed()) - << "ProductWithEntityMatrix does not support MPI yet.\n"; - - const IndexType number_of_output_entities = rOutput.GetContainer().size(); - const IndexType number_of_input_entities = rInput.GetContainer().size(); - - KRATOS_ERROR_IF_NOT(number_of_input_entities == rMatrix.size2()) - << "Input container size and matrix size2 mismatch. [ Container size = " - << number_of_input_entities << ", Matrix.size1() = " << rMatrix.size2() - << " ]. Followings are the given containers:" - << "\n\tInput data container : " << rInput - << "\n\tOutput data container: " << rOutput << "\n\t"; - - KRATOS_ERROR_IF_NOT(number_of_output_entities == rMatrix.size1()) - << "Output container size and matrix size1 mismatch. [ Container size = " - << number_of_output_entities << ", Matrix.size1() = " << rMatrix.size1() - << " ]. Followings are the given containers:" - << "\n\tInput data container : " << rInput - << "\n\tOutput data container: " << rOutput << "\n\t"; - - auto p_flat_data_expression = LiteralFlatExpression::Create(number_of_output_entities, rInput.GetItemShape()); - rOutput.SetExpression(p_flat_data_expression); - - const IndexType local_size = rInput.GetItemComponentCount(); - const auto& r_input_expression = rInput.GetExpression(); - auto& r_output_expression = *p_flat_data_expression; - - const double* a_values = rMatrix.value_data().begin(); - const IndexType* a_row_indices = rMatrix.index1_data().begin(); - const IndexType* a_col_indices = rMatrix.index2_data().begin(); - - IndexPartition(rMatrix.size1()).for_each([a_values, &r_input_expression, &r_output_expression, local_size, a_row_indices, a_col_indices](const IndexType i) { - const IndexType col_begin = a_row_indices[i]; - const IndexType col_end = a_row_indices[i + 1]; - const IndexType local_data_begin_index = i * local_size; - - for (IndexType d = 0; d < local_size; ++d) { - double result = 0.0; - for (IndexType j = col_begin; j < col_end; ++j) { - result += a_values[j] * r_input_expression.Evaluate(a_col_indices[j], a_col_indices[j] * local_size, d); - } - r_output_expression.SetData(local_data_begin_index, d, result); - } - }); -} - -template -void ContainerExpressionUtils::ProductWithEntityMatrix( - ContainerExpression& rOutput, - const Matrix& rMatrix, - const ContainerExpression& rInput) -{ - KRATOS_ERROR_IF(rInput.GetModelPart().IsDistributed() || - rOutput.GetModelPart().IsDistributed()) - << "ProductWithEntityMatrix does not support MPI yet.\n"; - - const IndexType number_of_output_entities = rOutput.GetContainer().size(); - const IndexType number_of_input_entities = rInput.GetContainer().size(); - - KRATOS_ERROR_IF_NOT(number_of_input_entities == rMatrix.size2()) - << "Input container size and matrix size2 mismatch. [ Container size = " - << number_of_input_entities << ", Matrix.size1() = " << rMatrix.size2() - << " ]. Followings are the given containers:" - << "\n\tInput data container : " << rInput - << "\n\tOutput data container: " << rOutput << "\n\t"; - - KRATOS_ERROR_IF_NOT(number_of_output_entities == rMatrix.size1()) - << "Output container size and matrix size1 mismatch. [ Container size = " - << number_of_output_entities << ", Matrix.size1() = " << rMatrix.size1() - << " ]. Followings are the given containers:" - << "\n\tInput data container : " << rInput - << "\n\tOutput data container: " << rOutput << "\n\t"; - - auto p_flat_data_expression = LiteralFlatExpression::Create(number_of_output_entities, rInput.GetItemShape()); - rOutput.SetExpression(p_flat_data_expression); - - const auto& r_input_expression = rInput.GetExpression(); - const IndexType local_size = rInput.GetItemComponentCount(); - auto& r_output_expression = *p_flat_data_expression; - - IndexPartition(rMatrix.size1()).for_each([&rMatrix, &r_input_expression, &r_output_expression, local_size](const IndexType i) { - const IndexType local_data_begin_index = i * local_size; - for (IndexType d = 0; d < local_size; ++d) { - double result = 0.0; - for (IndexType j = 0; j < rMatrix.size2(); ++j) { - result += rMatrix(i, j) * r_input_expression.Evaluate(j, j * local_size, d);; - } - r_output_expression.SetData(local_data_begin_index, d, result); - } - }); -} - -void ContainerExpressionUtils::Transpose( - Matrix& rOutput, - const Matrix& rInput) -{ - KRATOS_ERROR_IF(&rOutput == &rInput) - << "Please provide a matrix different to input matrix for output."; - - if (rOutput.size1() != rInput.size2() || rOutput.size2() != rInput.size1()) { - rOutput.resize(rInput.size2(), rInput.size1(), false); - } - - IndexPartition(rInput.size1()).for_each([&rInput, &rOutput](const IndexType i){ - for (IndexType j = 0; j < rInput.size2(); ++j) { - rOutput(j, i) = rInput(i, j); - } - }); -} - -void ContainerExpressionUtils::Transpose( - SparseMatrixType& rOutput, - const SparseMatrixType& rInput) -{ - if (rOutput.size1() != rInput.size2() || rOutput.size2() != rInput.size1()) { - rOutput.resize(rInput.size2(), rInput.size1(), false); - } - - const double* a_values = rInput.value_data().begin(); - const IndexType* a_row_indices = rInput.index1_data().begin(); - const IndexType* a_col_indices = rInput.index2_data().begin(); - - for (IndexType i = 0; i < rInput.size1(); ++i) { - const IndexType col_begin = a_row_indices[i]; - const IndexType col_end = a_row_indices[i + 1]; - - for (IndexType j = col_begin; j < col_end; ++j) { - rOutput.insert_element(a_col_indices[j], i, a_values[j]); - } - } -} - -template -void ContainerExpressionUtils::ComputeNumberOfNeighbourEntities( - ContainerExpression& rOutput) -{ - // clear the neighbour count storing variable - VariableUtils().SetNonHistoricalVariableToZero(TEMPORARY_SCALAR_VARIABLE_1, rOutput.GetModelPart().Nodes()); - - // create a dummy copy input data container to access its nodes and modify data - ContainerExpression dummy_input_container(rOutput.GetModelPart()); - - block_for_each(dummy_input_container.GetContainer(), [](auto& rEntity) { - auto& r_geometry = rEntity.GetGeometry(); - for (auto& r_node : r_geometry) { - AtomicAdd(r_node.GetValue(TEMPORARY_SCALAR_VARIABLE_1), 1.0); - } - }); - - rOutput.GetModelPart().GetCommunicator().AssembleNonHistoricalData(TEMPORARY_SCALAR_VARIABLE_1); - - // now read in the nodal data - VariableExpressionIO::Read(rOutput, &TEMPORARY_SCALAR_VARIABLE_1, false); -} - -template -void ContainerExpressionUtils::MapContainerVariableToNodalVariable( - ContainerExpression& rOutput, - const ContainerExpression& rInput, - const ContainerExpression& rNeighbourEntities) -{ - KRATOS_TRY - - KRATOS_ERROR_IF(&rOutput.GetModelPart() != &rInput.GetModelPart()) - << "Output container and input container model parts mismatch. " - "Followings are the container details:" - << "\n\tOutput container: " << rOutput - << "\n\tInput container : " << rInput << "\n"; - - KRATOS_ERROR_IF(&rOutput.GetModelPart() != &rNeighbourEntities.GetModelPart()) - << "Output container and neighbour entities container model parts mismatch. " - "Followings are the container details:" - << "\n\tOutput container : " << rOutput - << "\n\tNeighbour entities container: " << rNeighbourEntities << "\n"; - - KRATOS_ERROR_IF(rNeighbourEntities.GetItemComponentCount() != 1) - << "Neighbour entities container can only have data with dimensionality = 1" - << "\n\tNeighbour entities container:" << rNeighbourEntities << "\n"; - - // reset temporary variables - std::visit([&rOutput](auto&& p_variable) { - VariableUtils().SetNonHistoricalVariableToZero(*p_variable, rOutput.GetModelPart().Nodes()); - }, ContainerVariableDataHolderUtilsHelper::GetTemporaryVariable(rInput.GetItemShape())); - - // assign weights to nodes - VariableExpressionIO::Write(rNeighbourEntities, &TEMPORARY_SCALAR_VARIABLE_2, false); - - // create a dummy copy input data container to access its nodes and modify data - ContainerExpression dummy_input_container(rOutput.GetModelPart()); - - auto& r_container = dummy_input_container.GetContainer(); - auto& r_communicator = rOutput.GetModelPart().GetCommunicator(); - const IndexType number_of_entities = r_container.size(); - const auto& r_expression = rInput.GetExpression(); - - // now distribute the entity values to nodes - std::visit([&r_communicator, &r_container, &r_expression, number_of_entities](auto&& p_variable) { - // now create the variable_expression_data_io - auto p_variable_expression_data_io = ContainerVariableDataHolderUtilsHelper::GetVariableExpressionDataIO(*p_variable, r_expression.GetItemShape()); - - IndexPartition(number_of_entities).for_each(p_variable->Zero(), [&p_variable_expression_data_io, &p_variable, &r_container, &r_expression](const IndexType EntityIndex, auto& rValue) { - p_variable_expression_data_io->Assign(rValue, r_expression, EntityIndex); - - auto p_entity = (r_container.begin() + EntityIndex); - auto& r_geometry = p_entity->GetGeometry(); - for (auto& r_node : r_geometry) { - ContainerVariableDataHolderUtilsHelper::GenericAtomicAdd( - r_node.GetValue(*p_variable), - rValue / r_node.GetValue(TEMPORARY_SCALAR_VARIABLE_2)); - } - }); - - // now assemble data at nodes - r_communicator.AssembleNonHistoricalData(*p_variable); - - }, ContainerVariableDataHolderUtilsHelper::GetTemporaryVariable(rInput.GetItemShape())); - - // now read in the nodal data - std::visit([&rOutput](auto&& p_variable) { - VariableExpressionIO::Read(rOutput, p_variable, false); - }, ContainerVariableDataHolderUtilsHelper::GetTemporaryVariable(rInput.GetItemShape())); - - KRATOS_CATCH(""); -} - -template -void ContainerExpressionUtils::MapNodalVariableToContainerVariable( - ContainerExpression& rOutput, - const ContainerExpression& rInput) -{ - KRATOS_TRY - - KRATOS_ERROR_IF(&rOutput.GetModelPart() != &rInput.GetModelPart()) - << "Output container and input container model parts mismatch. " - "Followings are the container details:" - << "\n\tOutput container: " << rOutput - << "\n\tInput container : " << rInput << "\n"; - - std::visit([&rOutput, &rInput](auto&& p_variable) { - // now create the variable_expression_data_io - auto p_variable_expression_data_io = ContainerVariableDataHolderUtilsHelper::GetVariableExpressionDataIO(*p_variable, rInput.GetItemShape()); - - // first assign input data to nodes - VariableExpressionIO::Write(rInput, p_variable, false); - - const auto& r_output_container = rOutput.GetContainer(); - const IndexType number_of_entities = r_output_container.size(); - - // create output expression - auto p_flat_data_expression = LiteralFlatExpression::Create(number_of_entities, rInput.GetItemShape()); - auto& r_flat_data_expression = *p_flat_data_expression; - rOutput.SetExpression(p_flat_data_expression); - - // compute the entity values. - IndexPartition(number_of_entities).for_each([&p_variable_expression_data_io, &r_output_container, &r_flat_data_expression, &p_variable](const IndexType EntityIndex) { - const auto p_entity = (r_output_container.begin() + EntityIndex); - const auto& r_geometry = p_entity->GetGeometry(); - const IndexType number_of_nodes = r_geometry.size(); - - auto value = r_geometry[0].GetValue(*p_variable); - - for (IndexType i = 1; i < number_of_nodes; ++i) { - value += r_geometry[i].GetValue(*p_variable); - } - p_variable_expression_data_io->Read(r_flat_data_expression, EntityIndex, value / number_of_nodes); - }); - }, ContainerVariableDataHolderUtilsHelper::GetTemporaryVariable(rInput.GetItemShape())); - - KRATOS_CATCH(""); -} - -template -void ContainerExpressionUtils::ComputeNodalVariableProductWithEntityMatrix( - ContainerExpression& rOutput, - const ContainerExpression& rNodalValues, - const Variable& rMatrixVariable, - TContainerType& rEntities) -{ - KRATOS_TRY - - using tls_type = std::tuple; - - KRATOS_ERROR_IF(&rOutput.GetModelPart() != &rNodalValues.GetModelPart()) - << "Output container and input container model parts mismatch. " - "Followings are the container details:" - << "\n\tOutput container: " << rOutput - << "\n\tNodal container : " << rNodalValues << "\n"; - - KRATOS_ERROR_IF(ContainerExpression(rOutput.GetModelPart()).GetContainer().size() != rEntities.size()) - << "Provided entities container size mismatch with output container variable data holder size. " - << "[ Provided entities size = " << rEntities.size() - << ", output data container entities size = " << ContainerExpression(rOutput.GetModelPart()).GetContainer().size() << " ].\n"; - - const IndexType local_size = rNodalValues.GetItemComponentCount(); - - std::visit([&rOutput, &rNodalValues, &rMatrixVariable, &rEntities, local_size](auto&& p_variable_pair) { - const auto& r_input_variable = *std::get<0>(p_variable_pair); - const auto& r_output_variable = *std::get<1>(p_variable_pair); - - // now create the variable_expression_data_io - auto p_variable_expression_data_io = ContainerVariableDataHolderUtilsHelper::GetVariableExpressionDataIO(r_input_variable, rNodalValues.GetExpression().GetItemShape()); - - // assign nodal values - VariableExpressionIO::Write(rNodalValues, &r_input_variable, false); - - // clear the output variable - VariableUtils().SetNonHistoricalVariableToZero(r_output_variable, rOutput.GetModelPart().Nodes()); - - const auto& process_info = rOutput.GetModelPart().GetProcessInfo(); - - block_for_each(rEntities, tls_type(), [&p_variable_expression_data_io, &process_info, &rMatrixVariable, &r_input_variable, &r_output_variable, &rNodalValues, local_size](auto& rEntity, tls_type& rTLS) { - Matrix& r_entity_matrix = std::get<2>(rTLS); - - auto& r_geometry = rEntity.GetGeometry(); - - const IndexType number_of_nodes = r_geometry.size(); - - auto p_input_expression = LiteralFlatExpression::Create(number_of_nodes, rNodalValues.GetExpression().GetItemShape()); - auto p_output_expression = LiteralFlatExpression::Create(number_of_nodes, rNodalValues.GetExpression().GetItemShape()); - - for (IndexType i = 0; i < number_of_nodes; ++i) { - p_variable_expression_data_io->Read(*p_input_expression, i, r_geometry[i].GetValue(r_input_variable)); - } - - rEntity.Calculate(rMatrixVariable, r_entity_matrix, process_info); - - ContainerVariableDataHolderUtilsHelper::ComputeMatrixExpressionProduct( - *p_output_expression, r_entity_matrix, *p_input_expression, - number_of_nodes, local_size); - - // assign the vector to entity nodal values - for (IndexType i = 0; i < number_of_nodes; ++i) { - auto& r_node = r_geometry[i]; - r_node.SetLock(); - p_variable_expression_data_io->Assign(r_node.GetValue(r_output_variable), *p_output_expression, i); - r_node.UnSetLock(); - } - }); - - // assemble data for MPI - rOutput.GetModelPart().GetCommunicator().AssembleNonHistoricalData(r_output_variable); - - // now read the data - VariableExpressionIO::Read(rOutput, &r_output_variable, false); - }, ContainerVariableDataHolderUtilsHelper::GetTemporaryVariable1And2(rNodalValues.GetItemShape())); - - KRATOS_CATCH(""); -} - -template -ContainerExpression ContainerExpressionUtils::ExtractData( - ContainerExpression& rInputExpression, - ModelPart& rExtractionModelPart) -{ - KRATOS_TRY - - if (&rInputExpression.GetModelPart() == &rExtractionModelPart) { - return rInputExpression; - } - - auto& r_input_container = rInputExpression.GetContainer(); - const auto& r_input_expression = rInputExpression.GetExpression(); - const auto stride = rInputExpression.GetItemComponentCount(); - const auto number_of_input_entities = r_input_container.size(); - - ContainerExpression output_expression(rExtractionModelPart); - auto& r_output_container = output_expression.GetContainer(); - const auto number_of_output_entities = r_output_container.size(); - - // create flat expression to hold data - auto p_output_expression = LiteralFlatExpression::Create(number_of_output_entities, rInputExpression.GetItemShape()); - output_expression.SetExpression(p_output_expression); - - for (IndexType i_comp = 0; i_comp < stride; ++i_comp) { - // make the existing values to zero. - VariableUtils().SetNonHistoricalVariableToZero(TEMPORARY_SCALAR_VARIABLE_1, ModelPartUtils::GetContainer(rExtractionModelPart)); - VariableUtils().SetNonHistoricalVariableToZero(TEMPORARY_SCALAR_VARIABLE_1, ModelPartUtils::GetContainer(rInputExpression.GetModelPart())); - - // now write the values from input expression - IndexPartition(number_of_input_entities).for_each([&](const auto Index) { - (r_input_container.begin() + Index)->SetValue(TEMPORARY_SCALAR_VARIABLE_1, r_input_expression.Evaluate(Index, Index * stride, i_comp)); - }); - - // now read back to the output expression - IndexPartition(number_of_output_entities).for_each([&] (const auto Index) { - *(p_output_expression->begin() + Index * stride + i_comp) = (r_output_container.begin() + Index)->GetValue(TEMPORARY_SCALAR_VARIABLE_1); - }); - } - - return output_expression; - - KRATOS_CATCH(""); -} - -// template instantiations -#define KRATOS_INSTANTIATE_UTILITY_METHOD_FOR_CONTAINER_TYPE(ContainerType) \ - template KRATOS_API(OPTIMIZATION_APPLICATION) double ContainerExpressionUtils::EntityMaxNormL2(const ContainerExpression&); \ - template KRATOS_API(OPTIMIZATION_APPLICATION) void ContainerExpressionUtils::ProductWithEntityMatrix(ContainerExpression&, const typename UblasSpace::MatrixType&, const ContainerExpression&); \ - template KRATOS_API(OPTIMIZATION_APPLICATION) void ContainerExpressionUtils::ProductWithEntityMatrix(ContainerExpression&, const Matrix&, const ContainerExpression&); \ - template KRATOS_API(OPTIMIZATION_APPLICATION) ContainerExpression ContainerExpressionUtils::ExtractData(ContainerExpression&, ModelPart&); - -#define KRATOS_INSTANTIATE_NON_NODAL_UTILITY_METHOD_FOR_CONTAINER_TYPE(ContainerType) \ - template KRATOS_API(OPTIMIZATION_APPLICATION) void ContainerExpressionUtils::ComputeNumberOfNeighbourEntities(ContainerExpression&); \ - template KRATOS_API(OPTIMIZATION_APPLICATION) void ContainerExpressionUtils::MapContainerVariableToNodalVariable(ContainerExpression&, const ContainerExpression&, const ContainerExpression&); \ - template KRATOS_API(OPTIMIZATION_APPLICATION) void ContainerExpressionUtils::MapNodalVariableToContainerVariable(ContainerExpression&, const ContainerExpression&); \ - template KRATOS_API(OPTIMIZATION_APPLICATION) void ContainerExpressionUtils::ComputeNodalVariableProductWithEntityMatrix(ContainerExpression&, const ContainerExpression&, const Variable& rMatrixVariable, ContainerType&); - - -KRATOS_INSTANTIATE_UTILITY_METHOD_FOR_CONTAINER_TYPE(ModelPart::NodesContainerType) -KRATOS_INSTANTIATE_UTILITY_METHOD_FOR_CONTAINER_TYPE(ModelPart::ConditionsContainerType) -KRATOS_INSTANTIATE_UTILITY_METHOD_FOR_CONTAINER_TYPE(ModelPart::ElementsContainerType) - -KRATOS_INSTANTIATE_NON_NODAL_UTILITY_METHOD_FOR_CONTAINER_TYPE(ModelPart::ConditionsContainerType) -KRATOS_INSTANTIATE_NON_NODAL_UTILITY_METHOD_FOR_CONTAINER_TYPE(ModelPart::ElementsContainerType) - -#undef KRATOS_INSTANTIATE_UTILITY_METHOD_FOR_CONTAINER_TYPE -#undef KRATOS_INSTANTIATE_NON_NODAL_UTILITY_METHOD_FOR_CONTAINER_TYPE - -} diff --git a/applications/OptimizationApplication/custom_utilities/container_expression_utils.h b/applications/OptimizationApplication/custom_utilities/container_expression_utils.h deleted file mode 100644 index 70a1a2a6a9a0..000000000000 --- a/applications/OptimizationApplication/custom_utilities/container_expression_utils.h +++ /dev/null @@ -1,350 +0,0 @@ -// | / | -// ' / __| _` | __| _ \ __| -// . \ | ( | | ( |\__ ` -// _|\_\_| \__,_|\__|\___/ ____/ -// Multi-Physics -// -// License: BSD License -// license: OptimizationApplication/license.txt -// -// Main author: Suneth Warnakulasuriya -// - -#pragma once - -// System includes - -// Project includes -#include "includes/define.h" -#include "spaces/ublas_space.h" -#include "spatial_containers/spatial_containers.h" -#include "expression/container_expression.h" -#include "expression/expression_utils.h" -#include "collective_expression.h" - -// Application includes - -namespace Kratos -{ - -///@name Kratos Classes -///@{ - -class KRATOS_API(OPTIMIZATION_APPLICATION) ContainerExpressionUtils -{ -public: - ///@name Type definitions - ///@{ - - using IndexType = std::size_t; - - using SparseSpaceType = UblasSpace; - - using SparseMatrixType = SparseSpaceType::MatrixType; - - ///@} - ///@name Static operations - ///@{ - - /** - * @brief Calculate max L2 norm of the evaluated expression for each entity. - * - * This calculates L2 norm of the each entity expression by evaluating, and then returns - * the maximum of those. This is also an expensive operation. - * - * This method is optimized and compatible with OpenMP and MPI. - * - * @tparam TContainerType - * @param rContainer Container data - * @return double Max L2 norm - */ - template - static double EntityMaxNormL2(const ContainerExpression& rContainer); - - /** - * @brief Computes inner product between two container expressions by evaluating - * both expressions for each entity in their containers, hence this is an - * expensive operation. Both container expressions should have the same types of container expressions, - * therefore they may have the same container expressions lists. - * - * This method is optimized and compatible with OpenMP and MPI. - * - * @param rContainer1 Container expressions 1 - * @param rContainer2 Container expressions 2 - * @return double Output of the inner product. - */ - static double InnerProduct( - const CollectiveExpression& rContainer1, - const CollectiveExpression& rContainer2); - - /** - * @brief Calculates matrix vector product for container variable data - * - * This computes matrix and vector product between rMatrix and the container variable data rInput. - * This is an expensive operation since this involve evaluating the expression for each - * entity and doing matrix vector multiplication. - * - * This is only compatible with OpenMP. - * - * @tparam TContainerType - * @param rOutput Output container containing matrix vector multiplication. - * @param rMatrix Sparse matrix - * @param rInput Input container values to be used with matrix product. - */ - template - static void ProductWithEntityMatrix( - ContainerExpression& rOutput, - const SparseMatrixType& rMatrix, - const ContainerExpression& rInput); - - /** - * @brief Calculates matrix vector product for container variable data - * - * This computes matrix and vector product between rMatrix and the container variable data rInput. - * This is an expensive operation since this involve evaluating the expression for each - * entity and doing matrix vector multiplication. - * - * This is only compatible with OpenMP. - * - * @tparam TContainerType - * @param rOutput Output container containing matrix vector multiplication. - * @param rMatrix dense matrix - * @param rInput Input container values to be used with matrix product. - */ - template - static void ProductWithEntityMatrix( - ContainerExpression& rOutput, - const Matrix& rMatrix, - const ContainerExpression& rInput); - - /** - * @brief Transposes a dense matrix. - * - * This method is optimized for OpenMP. - * - * @param rOutput - * @param rInput - */ - static void Transpose( - Matrix& rOutput, - const Matrix& rInput); - - /** - * @brief Transposes a sparse matrix. - * - * This method is optimized for OpenMP. - * - * @param rOutput - * @param rInput - */ - static void Transpose( - SparseMatrixType& rOutput, - const SparseMatrixType& rInput); - - /** - * @brief Computes number ofneighbour entities for the container - * - * This method computes number of entities present around nodes in the - * given TContainerType in the model parts provided in the rOutput. - * - * This method is optimized and compatible with OpenMP and MPI. - * - * @tparam TContainerType - * @param rOutput Output containing number of entities around each node. - */ - template - static void ComputeNumberOfNeighbourEntities( - ContainerExpression& rOutput); - - /** - * @brief Maps container data to nodal data - * - * This method mapps container data given in rInput to nodal data (rOutput). Mapping is done using - * rNeighbourEntities (which should consist of number of neighbour entities surrounding each node.). - * - * All the model parts in rOutput, rInput and rNeighbourEntities should be the same. - * - * This method is optimized and compatible with OpenMP and MPI. - * - * @tparam TContainerType - * @param rOutput Output containing mapped nodal values. - * @param rInput Input containing values in the TContainerType which needs to be mapped to nodes. - * @param rNeighbourEntities Number of neighbour entities present around each node. - */ - template - static void MapContainerVariableToNodalVariable( - ContainerExpression& rOutput, - const ContainerExpression& rInput, - const ContainerExpression& rNeighbourEntities); - - /** - * @brief Maps nodal values to container variable data. - * - * This method maps nodal data to given container type. - * - * rOutput and rInput should have the same model part. - * - * This method is optimized and compatible with OpenMP and MPI. - * - * @tparam TContainerType - * @param rOutput Output containing mapped data. - * @param rInput Nodal data to be mapped to the other type of container. - */ - template - static void MapNodalVariableToContainerVariable( - ContainerExpression& rOutput, - const ContainerExpression& rInput); - - /** - * @brief Computes nodal and entity wise matrix multiplication. - * - * This method first distributes rNodalValues to nodes. Then it calculates - * the matrix from the rEntities using rMatrixVariable. Then nodal values of each - * entity in rEntities is computed. Finally the matrix (from rMatrixVariable in each entity) - * and vector (from nodal values for each entity taken from rNodalValues) multiplication is carried out. - * The solution of this multiplication is stored in rOutput. - * - * This method is optimized and compatible with OpenMP and MPI. - * - * @tparam TContainerType - * @param rOutput Output containing the matrix vectormultiplication - * @param rNodalValues Nodal values used as the vector. - * @param rMatrixVariable The variable used to obtain matrix from each variable. - * @param rEntities Entities to compute the matrix. - */ - template - static void ComputeNodalVariableProductWithEntityMatrix( - ContainerExpression& rOutput, - const ContainerExpression& rNodalValues, - const Variable& rMatrixVariable, - TContainerType& rEntities); - - /** - * @brief Extracts data which belongs to given model part from the expression. - * - * This method extracts data which belongs to entities in rExtractionModelPart from - * the given rInput container expression. - * - * @tparam TContainerType - * @param rInputExpression Input expression. - * @param rExtractionModelPart The model part where the entities are located to extract data. - * @return ContainerExpression Output expression with extracted data. - */ - template - static ContainerExpression ExtractData( - ContainerExpression& rInputExpression, - ModelPart& rExtractionModelPart); - - ///@} - ///@name Static operations derived from Kratos::ExpressionUtils - ///@{ - - #ifndef KRATOS_OPTAPP_EXPRESSION_UTILS_CEXP_METHOD_1 - #define KRATOS_OPTAPP_EXPRESSION_UTILS_CEXP_METHOD_1(METHOD_NAME) \ - static CollectiveExpression METHOD_NAME(const CollectiveExpression& rCollectiveExpression) \ - { \ - KRATOS_TRY \ - auto result = rCollectiveExpression; \ - auto r_list_of_container_expressions = result.GetContainerExpressions(); \ - for (IndexType i = 0; i < r_list_of_container_expressions.size(); ++i) { \ - std::visit( \ - [](auto& pResult) { \ - *pResult = ExpressionUtils::METHOD_NAME(*pResult); \ - }, \ - r_list_of_container_expressions[i]); \ - } \ - return result; \ - KRATOS_CATCH(""); \ - } - #endif - - #ifndef KRATOS_OPTAPP_EXPRESSION_UTILS_CEXP_METHOD_2 - #define KRATOS_OPTAPP_EXPRESSION_UTILS_CEXP_METHOD_2(METHOD_NAME) \ - static double METHOD_NAME(const CollectiveExpression& rCollectiveExpression) \ - { \ - KRATOS_TRY \ - double value = 0.0; \ - auto r_list_of_container_expressions = \ - rCollectiveExpression.GetContainerExpressions(); \ - for (IndexType i = 0; i < r_list_of_container_expressions.size(); ++i) { \ - value += std::visit( \ - [](const auto& pResult) { \ - return ExpressionUtils::METHOD_NAME(*pResult); \ - }, \ - r_list_of_container_expressions[i]); \ - } \ - return value; \ - KRATOS_CATCH(""); \ - } - #endif - - #ifndef KRATOS_OPTAPP_EXPRESSION_UTILS_CEXP_METHOD_3 - #define KRATOS_OPTAPP_EXPRESSION_UTILS_CEXP_METHOD_3(METHOD_NAME) \ - static CollectiveExpression METHOD_NAME( \ - const CollectiveExpression& rCollectiveExpression, const double V) \ - { \ - KRATOS_TRY \ - auto result = rCollectiveExpression; \ - auto r_list_of_container_expressions = result.GetContainerExpressions(); \ - for (IndexType i = 0; i < r_list_of_container_expressions.size(); ++i) { \ - std::visit( \ - [V](auto& pResult) { \ - *pResult = ExpressionUtils::METHOD_NAME(*pResult, V); \ - }, \ - r_list_of_container_expressions[i]); \ - } \ - return result; \ - KRATOS_CATCH(""); \ - } \ - static CollectiveExpression METHOD_NAME( \ - const CollectiveExpression& rCollectiveExpression1, \ - const CollectiveExpression& rCollectiveExpression2) \ - { \ - KRATOS_TRY \ - \ - KRATOS_ERROR_IF_NOT(rCollectiveExpression1.IsCompatibleWith(rCollectiveExpression2)) \ - << "Unsupported collective variable data holders provided for " \ - "\"" \ - << #METHOD_NAME << "\"." \ - << "\nLeft operand : " << rCollectiveExpression1 \ - << "\nRight operand: " << rCollectiveExpression2 << std::endl; \ - \ - auto result = rCollectiveExpression1; \ - auto r_list_of_container_expressions = result.GetContainerExpressions(); \ - const auto& r_right_container_expressions = \ - rCollectiveExpression2.GetContainerExpressions(); \ - for (IndexType i = 0; i < r_list_of_container_expressions.size(); ++i) { \ - std::visit( \ - [&r_right_container_expressions, i](auto& pResult) { \ - auto p_right = std::get>( \ - r_right_container_expressions[i]); \ - *pResult = ExpressionUtils::METHOD_NAME(*pResult, *p_right); \ - }, \ - r_list_of_container_expressions[i]); \ - } \ - return result; \ - \ - KRATOS_CATCH(""); \ - } - #endif - - KRATOS_OPTAPP_EXPRESSION_UTILS_CEXP_METHOD_1(Collapse) - KRATOS_OPTAPP_EXPRESSION_UTILS_CEXP_METHOD_1(Abs) - KRATOS_OPTAPP_EXPRESSION_UTILS_CEXP_METHOD_1(EntityMin) - KRATOS_OPTAPP_EXPRESSION_UTILS_CEXP_METHOD_1(EntityMax) - KRATOS_OPTAPP_EXPRESSION_UTILS_CEXP_METHOD_1(EntitySum) - KRATOS_OPTAPP_EXPRESSION_UTILS_CEXP_METHOD_2(Sum) - KRATOS_OPTAPP_EXPRESSION_UTILS_CEXP_METHOD_2(NormInf) - KRATOS_OPTAPP_EXPRESSION_UTILS_CEXP_METHOD_2(NormL2) - KRATOS_OPTAPP_EXPRESSION_UTILS_CEXP_METHOD_3(Pow) - KRATOS_OPTAPP_EXPRESSION_UTILS_CEXP_METHOD_3(Scale) - - #undef KRATOS_OPTAPP_EXPRESSION_UTILS_CEXP_METHOD_1 - #undef KRATOS_OPTAPP_EXPRESSION_UTILS_CEXP_METHOD_2 - #undef KRATOS_OPTAPP_EXPRESSION_UTILS_CEXP_METHOD_3 - - ///@} -}; - -///@} -} \ No newline at end of file diff --git a/applications/OptimizationApplication/custom_utilities/container_properties_data_io.h b/applications/OptimizationApplication/custom_utilities/container_properties_data_io.h deleted file mode 100644 index bf630c7549f5..000000000000 --- a/applications/OptimizationApplication/custom_utilities/container_properties_data_io.h +++ /dev/null @@ -1,58 +0,0 @@ -// | / | -// ' / __| _` | __| _ \ __| -// . \ | ( | | ( |\__ ` -// _|\_\_| \__,_|\__|\___/ ____/ -// Multi-Physics -// -// License: BSD License -// license: OptimizationApplication/license.txt -// -// Main author: Suneth Warnakulasuriya -// - -#pragma once - -// System includes - -// Project includes -#include "containers/variable.h" -#include "expression/container_data_io.h" -#include "includes/model_part.h" - -// Application includes - -namespace Kratos { - -///@name Kratos Classes -///@{ - -namespace ContainerDataIOTags { - struct Properties {}; -} // namespace Tags - -template <> -struct ContainerDataIO -{ - static constexpr std::string_view mInfo = "Properties"; - - template - static const TDataType& GetValue( - const TEntityType& rEntity, - const Variable& rVariable) - { - static_assert(!(std::is_same_v), "Properties retrieval is only supported for element and conditions."); - return rEntity.GetProperties().GetValue(rVariable); - } - - template - static void SetValue( - TEntityType& rEntity, - const Variable& rVariable, - const TDataType& rValue) - { - static_assert(!(std::is_same_v), "Properties setter is only supported for element and conditions."); - rEntity.GetProperties().SetValue(rVariable, rValue); - } -}; - -} // namespace Kratos \ No newline at end of file diff --git a/applications/OptimizationApplication/custom_utilities/properties_variable_expression_io.cpp b/applications/OptimizationApplication/custom_utilities/properties_variable_expression_io.cpp deleted file mode 100644 index d97c0d0655a7..000000000000 --- a/applications/OptimizationApplication/custom_utilities/properties_variable_expression_io.cpp +++ /dev/null @@ -1,166 +0,0 @@ -// | / | -// ' / __| _` | __| _ \ __| -// . \ | ( | | ( |\__ ` -// _|\_\_| \__,_|\__|\___/ ____/ -// Multi-Physics -// -// License: BSD License -// Kratos default license: kratos/license.txt -// -// Main authors: Suneth Warnakulasuriya -// - -// System includes -#include -#include - -// Project includes -#include "expression/container_data_io.h" -#include "expression/expression_io_utils.h" -#include "utilities/parallel_utilities.h" -#include "utilities/reduction_utilities.h" - -// Application includes -#include "custom_utilities/container_properties_data_io.h" - -// Include base h -#include "properties_variable_expression_io.h" - -namespace Kratos { - -PropertiesVariableExpressionIO::Input::Input( - const ModelPart& rModelPart, - const VariableType& rVariable, - Globals::DataLocation CurrentLocation) - : mpModelPart(&rModelPart), - mpVariable(rVariable), - mDataLocation(CurrentLocation) -{ -} - -Expression::Pointer PropertiesVariableExpressionIO::Input::Execute() const -{ - switch (mDataLocation) { - case Globals::DataLocation::Condition: - return ExpressionIOUtils::ReadToExpression, const VariableType>(mpModelPart->Conditions(), mpVariable, mpModelPart->GetCommunicator().GetDataCommunicator()); - case Globals::DataLocation::Element: - return ExpressionIOUtils::ReadToExpression, const VariableType>(mpModelPart->Elements(), mpVariable, mpModelPart->GetCommunicator().GetDataCommunicator()); - default: - KRATOS_ERROR << "Invalid container type. Only supports Condition and Element."; - break; - } - - return nullptr; -} - -PropertiesVariableExpressionIO::Output::Output( - ModelPart& rModelPart, - const VariableType& rVariable, - Globals::DataLocation CurrentLocation) - : mpModelPart(&rModelPart), - mpVariable(rVariable), - mDataLocation(CurrentLocation) -{ -} - -void PropertiesVariableExpressionIO::Output::Execute(const Expression& rExpression) -{ - KRATOS_TRY - - switch (mDataLocation) { - case Globals::DataLocation::Condition: - ExpressionIOUtils::WriteFromExpression, const VariableType>(mpModelPart->Conditions(), mpModelPart->GetCommunicator(), rExpression, mpVariable); - break; - case Globals::DataLocation::Element: - ExpressionIOUtils::WriteFromExpression, const VariableType>(mpModelPart->Elements(), mpModelPart->GetCommunicator(), rExpression, mpVariable); - break; - default: - KRATOS_ERROR << "Invalid container type. Only supports Condition and Element."; - break; - } - - KRATOS_CATCH(""); -} - -template -void PropertiesVariableExpressionIO::Read( - ContainerExpression& rContainerExpression, - const VariableType& rVariable) -{ - static_assert(!std::is_same_v, - "NodesContainerType expressions is not supported.\n"); - - auto p_expression = - Input(rContainerExpression.GetModelPart(), rVariable, - std::is_same_v - ? Globals::DataLocation::Condition - : Globals::DataLocation::Element) - .Execute(); - - // p_expression is nullptr if there are no items in the ModelParts relevant container. - // such as in ghost containers or interface containers. - if (p_expression.get() != nullptr) { - rContainerExpression.SetExpression(p_expression); - } -} - -template -void PropertiesVariableExpressionIO::Check( - const ContainerExpression& rContainerExpression, - const VariableType& rVariable) -{ - static_assert(!std::is_same_v, - "NodesContainerType expressions is not supported.\n"); - - std::visit([&rContainerExpression](auto pVariable){ - using data_type = typename std::remove_const_t>::Type; - - const auto& value_ptrs = block_for_each>>(rContainerExpression.GetContainer(), [pVariable](const auto& rEntity) -> data_type const* { - return &rEntity.GetProperties().GetValue(*pVariable); - }); - - const auto& r_data_communicator = rContainerExpression.GetModelPart().GetCommunicator().GetDataCommunicator(); - const auto number_of_values = r_data_communicator.SumAll(static_cast(value_ptrs.size())); - const auto number_of_entities = r_data_communicator.SumAll(static_cast(rContainerExpression.GetContainer().size())); - - KRATOS_ERROR_IF_NOT(number_of_values == number_of_entities) - << "Number of different values in properties for variable " - << pVariable->Name() << " is different from number of entities in " - << rContainerExpression.GetModelPart().FullName() - << ". [ Number of different values in properties = " << number_of_values - << ", number of entities = " << rContainerExpression.GetContainer().size() - << " ].\n"; - - }, rVariable); -} - -template -void PropertiesVariableExpressionIO::Write( - const ContainerExpression& rContainerExpression, - const VariableType& rVariable) -{ - static_assert(!std::is_same_v, - "NodesContainerType expressions is not supported.\n"); - - Output(*rContainerExpression.pGetModelPart(), rVariable, - std::is_same_v - ? Globals::DataLocation::Condition - : Globals::DataLocation::Element) - .Execute(rContainerExpression.GetExpression()); -} - -#define KRATOS_INSTANTIATE_ENTITY_CONTAINER_IO_METHODS(CONTAINER_TYPE, MESH_TYPE) \ - template KRATOS_API(OPTIMIZATION_APPLICATION) void PropertiesVariableExpressionIO::Read(ContainerExpression&, const PropertiesVariableExpressionIO::VariableType&); \ - template KRATOS_API(OPTIMIZATION_APPLICATION) void PropertiesVariableExpressionIO::Check(const ContainerExpression&, const PropertiesVariableExpressionIO::VariableType&); \ - template KRATOS_API(OPTIMIZATION_APPLICATION) void PropertiesVariableExpressionIO::Write(const ContainerExpression&, const PropertiesVariableExpressionIO::VariableType&); - -#define KRATOS_INSTANTIATE_ENTITY_CONTAINER_IO_METHODS_1(CONTAINER_TYPE) \ - KRATOS_INSTANTIATE_ENTITY_CONTAINER_IO_METHODS(CONTAINER_TYPE, MeshType::Local) - -KRATOS_INSTANTIATE_ENTITY_CONTAINER_IO_METHODS_1(ModelPart::ConditionsContainerType) -KRATOS_INSTANTIATE_ENTITY_CONTAINER_IO_METHODS_1(ModelPart::ElementsContainerType) - -#undef KRATOS_INSTANTIATE_ENTITY_CONTAINER_IO_METHODS -#undef KRATOS_INSTANTIATE_ENTITY_CONTAINER_IO_METHODS_1 - -} // namespace Kratos diff --git a/applications/OptimizationApplication/custom_utilities/properties_variable_expression_io.h b/applications/OptimizationApplication/custom_utilities/properties_variable_expression_io.h deleted file mode 100644 index 699eaa83f93f..000000000000 --- a/applications/OptimizationApplication/custom_utilities/properties_variable_expression_io.h +++ /dev/null @@ -1,153 +0,0 @@ -// | / | -// ' / __| _` | __| _ \ __| -// . \ | ( | | ( |\__ ` -// _|\_\_| \__,_|\__|\___/ ____/ -// Multi-Physics -// -// License: BSD License -// Kratos default license: kratos/license.txt -// -// Main authors: Suneth Warnakulasuriya -// - -#pragma once - -// System includes -#include - -// Project includes -#include "containers/array_1d.h" -#include "expression/container_expression.h" -#include "expression/expression_io.h" -#include "expression/traits.h" -#include "containers/variable.h" -#include "includes/define.h" -#include "includes/model_part.h" -#include "includes/global_variables.h" - -namespace Kratos { - - -class KRATOS_API(OPTIMIZATION_APPLICATION) PropertiesVariableExpressionIO -{ -public: - ///@name Type definitions - ///@{ - - using VariableType = std::variant< - const Variable*, - const Variable*, - const Variable>*, - const Variable>*, - const Variable>*, - const Variable>*, - const Variable*, - const Variable*>; - - ///} - ///@name Public classes - ///@{ - - class KRATOS_API(OPTIMIZATION_APPLICATION) Input : public ExpressionInput - { - public: - ///@name Type definitions - ///@{ - - KRATOS_CLASS_POINTER_DEFINITION(Input); - - ///@} - ///@name Life cycle - ///@{ - - Input( - const ModelPart& rModelPart, - const VariableType& rVariable, - Globals::DataLocation CurrentLocation); - - ///@} - ///@name Public operations - ///@{ - - Expression::Pointer Execute() const override; - - ///@} - - private: - ///@name Private member variables - ///@{ - - ModelPart const * mpModelPart; - - VariableType mpVariable; - - Globals::DataLocation mDataLocation; - - ///@} - - }; - - class KRATOS_API(OPTIMIZATION_APPLICATION) Output : public ExpressionOutput - { - public: - ///@name Type definitions - ///@{ - - KRATOS_CLASS_POINTER_DEFINITION(Output); - - ///@} - ///@name Life cycle - ///@{ - - Output( - ModelPart& rModelPart, - const VariableType& rVariable, - Globals::DataLocation CurrentLocation); - - ///@} - ///@name Public operations - ///@{ - - void Execute(const Expression& rExpression) override; - - ///@} - - private: - ///@name Private member variables - ///@{ - - ModelPart * mpModelPart; - - VariableType mpVariable; - - Globals::DataLocation mDataLocation; - - ///@} - - }; - - ///@} - ///@name Public static operations - ///@{ - - template - static void Read( - ContainerExpression& rContainerExpression, - const VariableType& rVariable); - - template - static void Check( - const ContainerExpression& rContainerExpression, - const VariableType& rVariable); - - template - static void Write( - const ContainerExpression& rContainerExpression, - const VariableType& rVariable); - - ///@} - -}; // class ExpressionIO - - -} // namespace Kratos diff --git a/applications/OptimizationApplication/tests/test_collective_expressions.py b/applications/OptimizationApplication/tests/test_collective_expressions.py deleted file mode 100644 index e9bd37bca031..000000000000 --- a/applications/OptimizationApplication/tests/test_collective_expressions.py +++ /dev/null @@ -1,761 +0,0 @@ -import numpy -import KratosMultiphysics as Kratos -import KratosMultiphysics.OptimizationApplication as KratosOA -import KratosMultiphysics.KratosUnittest as kratos_unittest - -class TestCollectiveExpressions(kratos_unittest.TestCase): - @classmethod - def setUpClass(cls): - cls.model = Kratos.Model() - cls.model_part = cls.model.CreateModelPart("test") - cls.model_part.AddNodalSolutionStepVariable(Kratos.DENSITY) - cls.model_part.AddNodalSolutionStepVariable(Kratos.PRESSURE) - cls.model_part.AddNodalSolutionStepVariable(Kratos.ACCELERATION) - cls.model_part.AddNodalSolutionStepVariable(Kratos.VELOCITY) - - number_of_nodes = 3 - for id in range(1, number_of_nodes + 1): - node = cls.model_part.CreateNewNode(id, id, id+1, id+2) - node.SetSolutionStepValue(Kratos.VELOCITY, Kratos.Array3([id+3, id+4, id+5])) - node.SetSolutionStepValue(Kratos.PRESSURE, id+3) - node.SetValue(Kratos.PRESSURE, id+3) - node.SetValue(Kratos.VELOCITY, Kratos.Array3([id+3, id+4, id+5])) - - number_of_conditions = 4 - for id in range(1, number_of_conditions + 1): - properties = cls.model_part.CreateNewProperties(id) - properties.SetValue(Kratos.PRESSURE, id+400) - properties.SetValue(Kratos.VELOCITY, Kratos.Array3([id+500, id+600, id+700])) - condition = cls.model_part.CreateNewCondition("LineCondition2D2N", id + 1, [(id % number_of_nodes) + 1, ((id + 1) % number_of_nodes) + 1 ], properties) - condition.SetValue(Kratos.PRESSURE, id+4) - condition.SetValue(Kratos.VELOCITY, Kratos.Array3([id+5, id+6, id+7])) - - number_of_elements = 5 - for id in range(1, number_of_elements + 1): - properties = cls.model_part.CreateNewProperties(id + number_of_conditions) - properties.SetValue(Kratos.PRESSURE, id+500) - properties.SetValue(Kratos.VELOCITY, Kratos.Array3([id+600, id+700, id+800])) - element = cls.model_part.CreateNewElement("Element2D3N", id + 2, [(id % number_of_nodes) + 1, ((id + 1) % number_of_nodes) + 1, ((id + 2) % number_of_nodes) + 1 ], properties) - element.SetValue(Kratos.PRESSURE, id+5) - element.SetValue(Kratos.VELOCITY, Kratos.Array3([id+6, id+7, id+8])) - - def test_CollectiveExpressionsAdd(self): - a = Kratos.Expression.NodalExpression(self.model_part) - b = Kratos.Expression.ElementExpression(self.model_part) - - Kratos.Expression.VariableExpressionIO.Read(a, Kratos.VELOCITY, True) - KratosOA.PropertiesVariableExpressionIO.Read(b, Kratos.PRESSURE) - - collective_1 = KratosOA.CollectiveExpression() - collective_1.Add(a) - collective_1.Add(b) - - collective_2 = KratosOA.CollectiveExpression() - collective_2.Add(a) - collective_2.Add(b) - - collective_3 = collective_1 * 10 + collective_2 - collective_3 += collective_1 - collective_4 = collective_3 + 4 - collective_4 += 10 - collective_4 += collective_1.Clone() - - Kratos.Expression.VariableExpressionIO.Write(collective_4.GetContainerExpressions()[0], Kratos.ACCELERATION, True) - KratosOA.PropertiesVariableExpressionIO.Write(collective_4.GetContainerExpressions()[1], Kratos.DENSITY) - - for node in self.model_part.Nodes: - self.assertVectorAlmostEqual(node.GetSolutionStepValue(Kratos.ACCELERATION), node.GetSolutionStepValue(Kratos.VELOCITY) * 13 + Kratos.Array3([14, 14, 14]), 12) - for element in self.model_part.Elements: - self.assertEqual(element.Properties[Kratos.DENSITY], element.Properties[Kratos.PRESSURE] * 13 + 14, 12) - - def test_CollectiveExpressionsSub(self): - a = Kratos.Expression.NodalExpression(self.model_part) - b = Kratos.Expression.ElementExpression(self.model_part) - - Kratos.Expression.VariableExpressionIO.Read(a, Kratos.VELOCITY, True) - KratosOA.PropertiesVariableExpressionIO.Read(b, Kratos.PRESSURE) - - collective_1 = KratosOA.CollectiveExpression() - collective_1.Add(a) - collective_1.Add(b) - - collective_2 = KratosOA.CollectiveExpression() - collective_2.Add(a) - collective_2.Add(b) - - collective_3 = collective_1 * 10 - collective_2 - collective_3 -= collective_1 - collective_4 = collective_3 - 4 - collective_4 -= 10 - collective_4 -= collective_1.Clone() - - Kratos.Expression.VariableExpressionIO.Write(collective_4.GetContainerExpressions()[0], Kratos.ACCELERATION, True) - KratosOA.PropertiesVariableExpressionIO.Write(collective_4.GetContainerExpressions()[1], Kratos.DENSITY) - - for node in self.model_part.Nodes: - self.assertVectorAlmostEqual(node.GetSolutionStepValue(Kratos.ACCELERATION), node.GetSolutionStepValue(Kratos.VELOCITY) * 7 - Kratos.Array3([14, 14, 14]), 12) - for element in self.model_part.Elements: - self.assertEqual(element.Properties[Kratos.DENSITY], element.Properties[Kratos.PRESSURE] * 7 - 14, 12) - - def test_CollectiveExpressionsMul(self): - a = Kratos.Expression.NodalExpression(self.model_part) - b = Kratos.Expression.ElementExpression(self.model_part) - - Kratos.Expression.VariableExpressionIO.Read(a, Kratos.VELOCITY, True) - KratosOA.PropertiesVariableExpressionIO.Read(b, Kratos.PRESSURE) - - collective_1 = KratosOA.CollectiveExpression() - collective_1.Add(a) - collective_1.Add(b) - - collective_2 = KratosOA.CollectiveExpression() - collective_2.Add(a) - collective_2.Add(b) - - collective_3 = collective_1 * 10 - collective_3 *= 2 - - Kratos.Expression.VariableExpressionIO.Write(collective_3.GetContainerExpressions()[0], Kratos.ACCELERATION, True) - KratosOA.PropertiesVariableExpressionIO.Write(collective_3.GetContainerExpressions()[1], Kratos.DENSITY) - - for node in self.model_part.Nodes: - self.assertVectorAlmostEqual(node.GetSolutionStepValue(Kratos.ACCELERATION), node.GetSolutionStepValue(Kratos.VELOCITY) * 20, 12) - for element in self.model_part.Elements: - self.assertEqual(element.Properties[Kratos.DENSITY], element.Properties[Kratos.PRESSURE] * 20, 12) - - def test_CollectiveExpressionsDiv(self): - a = Kratos.Expression.NodalExpression(self.model_part) - b = Kratos.Expression.ElementExpression(self.model_part) - - Kratos.Expression.VariableExpressionIO.Read(a, Kratos.VELOCITY, True) - KratosOA.PropertiesVariableExpressionIO.Read(b, Kratos.PRESSURE) - - collective_1 = KratosOA.CollectiveExpression() - collective_1.Add(a) - collective_1.Add(b) - - collective_2 = KratosOA.CollectiveExpression() - collective_2.Add(a) - collective_2.Add(b) - - collective_3 = collective_1 / 4 - collective_3 /= 2 - - Kratos.Expression.VariableExpressionIO.Write(collective_3.GetContainerExpressions()[0], Kratos.ACCELERATION, True) - KratosOA.PropertiesVariableExpressionIO.Write(collective_3.GetContainerExpressions()[1], Kratos.DENSITY) - - for node in self.model_part.Nodes: - self.assertVectorAlmostEqual(node.GetSolutionStepValue(Kratos.ACCELERATION), node.GetSolutionStepValue(Kratos.VELOCITY) / 8, 12) - for element in self.model_part.Elements: - self.assertEqual(element.Properties[Kratos.DENSITY], element.Properties[Kratos.PRESSURE] / 8, 12) - - def test_CollectiveExpressionsPow(self): - a = Kratos.Expression.NodalExpression(self.model_part) - b = Kratos.Expression.ElementExpression(self.model_part) - - Kratos.Expression.VariableExpressionIO.Read(a, Kratos.VELOCITY, True) - KratosOA.PropertiesVariableExpressionIO.Read(b, Kratos.PRESSURE) - - collective_1 = KratosOA.CollectiveExpression() - collective_1.Add(a) - collective_1.Add(b) - - collective_2 = KratosOA.CollectiveExpression() - collective_2.Add(a) - collective_2.Add(b) - - collective_3 = collective_1 ** (collective_1 / 1e+3) - collective_3 **= 2 - - Kratos.Expression.VariableExpressionIO.Write(collective_3.GetContainerExpressions()[0], Kratos.ACCELERATION, True) - KratosOA.PropertiesVariableExpressionIO.Write(collective_3.GetContainerExpressions()[1], Kratos.DENSITY) - - for node in self.model_part.Nodes: - v = node.GetSolutionStepValue(Kratos.VELOCITY) - self.assertVectorAlmostEqual(node.GetSolutionStepValue(Kratos.ACCELERATION), Kratos.Array3([v[0]**(2*v[0]/1e+3), v[1]**(2*v[1]/1e+3), v[2]**(2*v[2]/1e+3)]) , 12) - for element in self.model_part.Elements: - self.assertAlmostEqual(element.Properties[Kratos.DENSITY], element.Properties[Kratos.PRESSURE] ** (2 * element.Properties[Kratos.PRESSURE] / 1e+3), 12) - - def test_CollectiveExpressionsNeg(self): - a = Kratos.Expression.NodalExpression(self.model_part) - b = Kratos.Expression.ElementExpression(self.model_part) - - Kratos.Expression.VariableExpressionIO.Read(a, Kratos.VELOCITY, True) - KratosOA.PropertiesVariableExpressionIO.Read(b, Kratos.PRESSURE) - - collective_1 = KratosOA.CollectiveExpression() - collective_1.Add(a) - collective_1.Add(b) - - collective_2 = KratosOA.CollectiveExpression() - collective_2.Add(a) - collective_2.Add(b) - - collective_3 = -collective_1 - - Kratos.Expression.VariableExpressionIO.Write(collective_3.GetContainerExpressions()[0], Kratos.ACCELERATION, True) - KratosOA.PropertiesVariableExpressionIO.Write(collective_3.GetContainerExpressions()[1], Kratos.DENSITY) - - for node in self.model_part.Nodes: - v = node.GetSolutionStepValue(Kratos.VELOCITY) - self.assertVectorAlmostEqual(node.GetSolutionStepValue(Kratos.ACCELERATION), v*(-1) , 12) - for element in self.model_part.Elements: - self.assertEqual(element.Properties[Kratos.DENSITY], -element.Properties[Kratos.PRESSURE], 12) - - def test_IsCompatibleWith(self): - additional_model_part = self.model.CreateModelPart("additional_model_part") - - diff_size_model_part = self.model.CreateModelPart("diff_size_model_part") - - for properties in self.model_part.GetProperties(): - additional_model_part.AddProperties(properties) - - for node in self.model_part.Nodes: - additional_model_part.AddNode(node) - - for condition in self.model_part.Conditions: - additional_model_part.AddCondition(condition) - - for element in self.model_part.Elements: - additional_model_part.AddElement(element) - - a = Kratos.Expression.NodalExpression(self.model_part) - b = Kratos.Expression.ElementExpression(self.model_part) - c = Kratos.Expression.NodalExpression(additional_model_part) - d = Kratos.Expression.NodalExpression(diff_size_model_part) - - Kratos.Expression.VariableExpressionIO.Read(a, Kratos.VELOCITY, True) - Kratos.Expression.VariableExpressionIO.Read(b, Kratos.PRESSURE) - Kratos.Expression.VariableExpressionIO.Read(c, Kratos.VELOCITY, True) - Kratos.Expression.VariableExpressionIO.Read(d, Kratos.VELOCITY, True) - - collective_1 = KratosOA.CollectiveExpression([a, b]) - self.assertTrue(collective_1.IsCompatibleWith(KratosOA.CollectiveExpression([a, b]))) - self.assertFalse(collective_1.IsCompatibleWith(KratosOA.CollectiveExpression([a]))) - self.assertFalse(collective_1.IsCompatibleWith(KratosOA.CollectiveExpression([b, a]))) - self.assertTrue(collective_1.IsCompatibleWith(KratosOA.CollectiveExpression([c, b]))) - self.assertFalse(collective_1.IsCompatibleWith(KratosOA.CollectiveExpression([c, d]))) - - def test_ReadEvaluate1(self): - a = Kratos.Expression.NodalExpression(self.model_part) - b = Kratos.Expression.NodalExpression(self.model_part) - c = Kratos.Expression.ConditionExpression(self.model_part) - d = Kratos.Expression.ElementExpression(self.model_part) - - collective = KratosOA.CollectiveExpression([a, b, c, d]) - - # reads VELOCITY from different container expressions - ceio = KratosOA.CollectiveExpressionIO - historical = ceio.HistoricalVariable(Kratos.VELOCITY) - non_historical = ceio.NonHistoricalVariable(Kratos.VELOCITY) - KratosOA.CollectiveExpressionIO.Read(collective, [historical, non_historical, non_historical, non_historical]) - - # do some calculations on all container expressions. these are lazy expressions, hence light wieght operations. - collective += 2 - collective *= 3 - - # finally evaluate the lazy expressions and put it to a numpy continuous array - result = collective.Evaluate() - self.assertEqual(result.shape, (self.model_part.NumberOfNodes() * 2 + self.model_part.NumberOfConditions() + self.model_part.NumberOfElements(), 3)) - - # now check - offset = 0 - for i, node in enumerate(self.model_part.Nodes): - velocity = node.GetSolutionStepValue(Kratos.VELOCITY) - self.assertEqual((velocity[0] + 2) * 3, result[i + offset, 0]) - self.assertEqual((velocity[1] + 2) * 3, result[i + offset, 1]) - self.assertEqual((velocity[2] + 2) * 3, result[i + offset, 2]) - - offset += self.model_part.NumberOfNodes() - for i, node in enumerate(self.model_part.Nodes): - velocity = node.GetValue(Kratos.VELOCITY) - self.assertEqual((velocity[0] + 2) * 3, result[i + offset, 0]) - self.assertEqual((velocity[1] + 2) * 3, result[i + offset, 1]) - self.assertEqual((velocity[2] + 2) * 3, result[i + offset, 2]) - - offset += self.model_part.NumberOfNodes() - for i, condition in enumerate(self.model_part.Conditions): - velocity = condition.GetValue(Kratos.VELOCITY) - self.assertEqual((velocity[0] + 2) * 3, result[i + offset, 0]) - self.assertEqual((velocity[1] + 2) * 3, result[i + offset, 1]) - self.assertEqual((velocity[2] + 2) * 3, result[i + offset, 2]) - - offset += self.model_part.NumberOfConditions() - for i, element in enumerate(self.model_part.Elements): - velocity = element.GetValue(Kratos.VELOCITY) - self.assertEqual((velocity[0] + 2) * 3, result[i + offset, 0]) - self.assertEqual((velocity[1] + 2) * 3, result[i + offset, 1]) - self.assertEqual((velocity[2] + 2) * 3, result[i + offset, 2]) - - def test_ReadEvaluate2(self): - a = Kratos.Expression.NodalExpression(self.model_part) - b = Kratos.Expression.NodalExpression(self.model_part) - c = Kratos.Expression.ConditionExpression(self.model_part) - d = Kratos.Expression.ElementExpression(self.model_part) - - collective = KratosOA.CollectiveExpression([a, b, c, d]) - - # reads VELOCITY from different container expressions - ceio = KratosOA.CollectiveExpressionIO - historical = ceio.HistoricalVariable - non_historical = ceio.NonHistoricalVariable - KratosOA.CollectiveExpressionIO.Read(collective, [historical(Kratos.VELOCITY), non_historical(Kratos.PRESSURE), non_historical(Kratos.VELOCITY), non_historical(Kratos.PRESSURE)]) - - # do some calculations on all container expressions. these are lazy expressions, hence light wieght operations. - collective += 2 - collective *= 3 - - # finally evaluate the lazy expressions and put it to a numpy continuous array - result = collective.Evaluate() - self.assertEqual(result.shape, (self.model_part.NumberOfNodes() * 4 + self.model_part.NumberOfConditions() * 3 + self.model_part.NumberOfElements(), )) - - # now check - index = 0 - for node in self.model_part.Nodes: - velocity = node.GetSolutionStepValue(Kratos.VELOCITY) - self.assertEqual((velocity[0] + 2) * 3, result[index]) - self.assertEqual((velocity[1] + 2) * 3, result[index + 1]) - self.assertEqual((velocity[2] + 2) * 3, result[index + 2]) - index += 3 - - for node in self.model_part.Nodes: - pressure = node.GetValue(Kratos.PRESSURE) - self.assertEqual((pressure + 2) * 3, result[index]) - index += 1 - - for condition in self.model_part.Conditions: - velocity = condition.GetValue(Kratos.VELOCITY) - self.assertEqual((velocity[0] + 2) * 3, result[index]) - self.assertEqual((velocity[1] + 2) * 3, result[index + 1]) - self.assertEqual((velocity[2] + 2) * 3, result[index + 2]) - index += 3 - - for element in self.model_part.Elements: - pressure = element.GetValue(Kratos.PRESSURE) - self.assertEqual((pressure + 2) * 3, result[index]) - index += 1 - - def test_ReadEvaluate3(self): - a = Kratos.Expression.NodalExpression(self.model_part) - b = Kratos.Expression.NodalExpression(self.model_part) - c = Kratos.Expression.ConditionExpression(self.model_part) - d = Kratos.Expression.ElementExpression(self.model_part) - - collective = KratosOA.CollectiveExpression([a, b, c, d]) - - data = numpy.arange(1, self.model_part.NumberOfNodes() * 4 + self.model_part.NumberOfConditions() * 3 + self.model_part.NumberOfElements() + 1, 1.0) - - # here we copy data - KratosOA.CollectiveExpressionIO.Read(collective, data, [[3], [], [3], []]) - - # do some calculations on all container expressions. these are lazy expressions, hence light wieght operations. - collective += 2 - collective *= 3 - - ceio = KratosOA.CollectiveExpressionIO - historical = ceio.HistoricalVariable - non_historical = ceio.NonHistoricalVariable - KratosOA.CollectiveExpressionIO.Write(collective, [historical(Kratos.ACCELERATION), non_historical(Kratos.DENSITY), non_historical(Kratos.ACCELERATION), non_historical(Kratos.DENSITY)]) - - # now check - index = 0 - for node in self.model_part.Nodes: - acceleration = node.GetSolutionStepValue(Kratos.ACCELERATION) - self.assertEqual(acceleration[0], (data[index] + 2) * 3) - self.assertEqual(acceleration[1], (data[index + 1] + 2) * 3) - self.assertEqual(acceleration[2], (data[index + 2] + 2) * 3) - index += 3 - - for node in self.model_part.Nodes: - pressure = node.GetValue(Kratos.DENSITY) - self.assertEqual(pressure, (data[index] + 2) * 3) - index += 1 - - for condition in self.model_part.Conditions: - acceleration = condition.GetValue(Kratos.ACCELERATION) - self.assertEqual(acceleration[0], (data[index] + 2) * 3) - self.assertEqual(acceleration[1], (data[index + 1] + 2) * 3) - self.assertEqual(acceleration[2], (data[index + 2] + 2) * 3) - index += 3 - - for element in self.model_part.Elements: - pressure = element.GetValue(Kratos.DENSITY) - self.assertEqual(pressure, (data[index] + 2) * 3) - index += 1 - - def test_ReadEvaluate4(self): - a = Kratos.Expression.NodalExpression(self.model_part) - b = Kratos.Expression.NodalExpression(self.model_part) - c = Kratos.Expression.ConditionExpression(self.model_part) - d = Kratos.Expression.ElementExpression(self.model_part) - - collective = KratosOA.CollectiveExpression([a, b, c, d]) - - data = numpy.arange(1, self.model_part.NumberOfNodes() * 6 + self.model_part.NumberOfConditions() * 3 + self.model_part.NumberOfElements() * 3 + 1, 1.0) - data = data.reshape((self.model_part.NumberOfNodes() * 2 + self.model_part.NumberOfConditions() + self.model_part.NumberOfElements(), 3)) - - # here we copy data - KratosOA.CollectiveExpressionIO.Read(collective, data) - - # do some calculations on all container expressions. these are lazy expressions, hence light wieght operations. - collective += 2 - collective *= 3 - - ceio = KratosOA.CollectiveExpressionIO - historical = ceio.HistoricalVariable - non_historical = ceio.NonHistoricalVariable - KratosOA.CollectiveExpressionIO.Write(collective, [historical(Kratos.ACCELERATION), non_historical(Kratos.ACCELERATION), non_historical(Kratos.ACCELERATION), non_historical(Kratos.ACCELERATION)]) - - # now check - offset = 0 - for i, node in enumerate(self.model_part.Nodes): - acceleration = node.GetSolutionStepValue(Kratos.ACCELERATION) - self.assertEqual(acceleration[0], (data[i + offset, 0] + 2) * 3) - self.assertEqual(acceleration[1], (data[i + offset, 1] + 2) * 3) - self.assertEqual(acceleration[2], (data[i + offset, 2] + 2) * 3) - - offset += self.model_part.NumberOfNodes() - for i, node in enumerate(self.model_part.Nodes): - acceleration = node.GetValue(Kratos.ACCELERATION) - self.assertEqual(acceleration[0], (data[i + offset, 0] + 2) * 3) - self.assertEqual(acceleration[1], (data[i + offset, 1] + 2) * 3) - self.assertEqual(acceleration[2], (data[i + offset, 2] + 2) * 3) - - offset += self.model_part.NumberOfNodes() - for i, condition in enumerate(self.model_part.Conditions): - acceleration = condition.GetValue(Kratos.ACCELERATION) - self.assertEqual(acceleration[0], (data[i + offset, 0] + 2) * 3) - self.assertEqual(acceleration[1], (data[i + offset, 1] + 2) * 3) - self.assertEqual(acceleration[2], (data[i + offset, 2] + 2) * 3) - - offset += self.model_part.NumberOfConditions() - for i, element in enumerate(self.model_part.Elements): - acceleration = element.GetValue(Kratos.ACCELERATION) - self.assertEqual(acceleration[0], (data[i + offset, 0] + 2) * 3) - self.assertEqual(acceleration[1], (data[i + offset, 1] + 2) * 3) - self.assertEqual(acceleration[2], (data[i + offset, 2] + 2) * 3) - - def test_Move(self): - a = Kratos.Expression.NodalExpression(self.model_part) - b = Kratos.Expression.NodalExpression(self.model_part) - c = Kratos.Expression.ConditionExpression(self.model_part) - d = Kratos.Expression.ElementExpression(self.model_part) - - collective = KratosOA.CollectiveExpression([a, b, c, d]) - - data = numpy.arange(1, self.model_part.NumberOfNodes() * 4 + self.model_part.NumberOfConditions() * 3 + self.model_part.NumberOfElements() + 1, 1.0) - - # here we move data. The life time is not managed by the collective. If moved data is destroyed, then use of collective can seg fault. - KratosOA.CollectiveExpressionIO.Move(collective, data, [[3], [], [3], []]) - - # do some calculations on all container expressions. these are lazy expressions, hence light wieght operations. - collective += 2 - collective *= 3 - - ceio = KratosOA.CollectiveExpressionIO - historical = ceio.HistoricalVariable - non_historical = ceio.NonHistoricalVariable - KratosOA.CollectiveExpressionIO.Write(collective, [historical(Kratos.ACCELERATION), non_historical(Kratos.DENSITY), non_historical(Kratos.ACCELERATION), non_historical(Kratos.DENSITY)]) - - # now check for initial values - index = 0 - for node in self.model_part.Nodes: - acceleration = node.GetSolutionStepValue(Kratos.ACCELERATION) - self.assertEqual(acceleration[0], (data[index] + 2) * 3) - self.assertEqual(acceleration[1], (data[index + 1] + 2) * 3) - self.assertEqual(acceleration[2], (data[index + 2] + 2) * 3) - index += 3 - - for node in self.model_part.Nodes: - pressure = node.GetValue(Kratos.DENSITY) - self.assertEqual(pressure, (data[index] + 2) * 3) - index += 1 - - for condition in self.model_part.Conditions: - acceleration = condition.GetValue(Kratos.ACCELERATION) - self.assertEqual(acceleration[0], (data[index] + 2) * 3) - self.assertEqual(acceleration[1], (data[index + 1] + 2) * 3) - self.assertEqual(acceleration[2], (data[index + 2] + 2) * 3) - index += 3 - - for element in self.model_part.Elements: - pressure = element.GetValue(Kratos.DENSITY) - self.assertEqual(pressure, (data[index] + 2) * 3) - index += 1 - - # now change the numpy array to check whether we are still referening to data from numpy arraydata - data += 1.0 - KratosOA.CollectiveExpressionIO.Write(collective, [historical(Kratos.ACCELERATION), non_historical(Kratos.DENSITY), non_historical(Kratos.ACCELERATION), non_historical(Kratos.DENSITY)]) - - # now check for changed values - index = 0 - for node in self.model_part.Nodes: - acceleration = node.GetSolutionStepValue(Kratos.ACCELERATION) - self.assertEqual(acceleration[0], (data[index] + 2) * 3) - self.assertEqual(acceleration[1], (data[index + 1] + 2) * 3) - self.assertEqual(acceleration[2], (data[index + 2] + 2) * 3) - index += 3 - - for node in self.model_part.Nodes: - pressure = node.GetValue(Kratos.DENSITY) - self.assertEqual(pressure, (data[index] + 2) * 3) - index += 1 - - for condition in self.model_part.Conditions: - acceleration = condition.GetValue(Kratos.ACCELERATION) - self.assertEqual(acceleration[0], (data[index] + 2) * 3) - self.assertEqual(acceleration[1], (data[index + 1] + 2) * 3) - self.assertEqual(acceleration[2], (data[index + 2] + 2) * 3) - index += 3 - - for element in self.model_part.Elements: - pressure = element.GetValue(Kratos.DENSITY) - self.assertEqual(pressure, (data[index] + 2) * 3) - index += 1 - - def test_Move2(self): - a = Kratos.Expression.NodalExpression(self.model_part) - b = Kratos.Expression.NodalExpression(self.model_part) - c = Kratos.Expression.ConditionExpression(self.model_part) - d = Kratos.Expression.ElementExpression(self.model_part) - - collective = KratosOA.CollectiveExpression([a, b, c, d]) - - data = numpy.arange(1, self.model_part.NumberOfNodes() * 6 + self.model_part.NumberOfConditions() * 3 + self.model_part.NumberOfElements() * 3 + 1, 1.0) - data = data.reshape((self.model_part.NumberOfNodes() * 2 + self.model_part.NumberOfConditions() + self.model_part.NumberOfElements(), 3)) - - # here we move data. The life time is not managed by the collective. If moved data is destroyed, then use of collective can seg fault. - KratosOA.CollectiveExpressionIO.Move(collective, data) - - # do some calculations on all container expressions. these are lazy expressions, hence light wieght operations. - collective += 2 - collective *= 3 - - ceio = KratosOA.CollectiveExpressionIO - historical = ceio.HistoricalVariable - non_historical = ceio.NonHistoricalVariable - KratosOA.CollectiveExpressionIO.Write(collective, [historical(Kratos.ACCELERATION), non_historical(Kratos.ACCELERATION), non_historical(Kratos.ACCELERATION), non_historical(Kratos.ACCELERATION)]) - - # now check for initial values - offset = 0 - for i, node in enumerate(self.model_part.Nodes): - acceleration = node.GetSolutionStepValue(Kratos.ACCELERATION) - self.assertEqual(acceleration[0], (data[i + offset, 0] + 2) * 3) - self.assertEqual(acceleration[1], (data[i + offset, 1] + 2) * 3) - self.assertEqual(acceleration[2], (data[i + offset, 2] + 2) * 3) - - offset += self.model_part.NumberOfNodes() - for i, node in enumerate(self.model_part.Nodes): - acceleration = node.GetValue(Kratos.ACCELERATION) - self.assertEqual(acceleration[0], (data[i + offset, 0] + 2) * 3) - self.assertEqual(acceleration[1], (data[i + offset, 1] + 2) * 3) - self.assertEqual(acceleration[2], (data[i + offset, 2] + 2) * 3) - - offset += self.model_part.NumberOfNodes() - for i, condition in enumerate(self.model_part.Conditions): - acceleration = condition.GetValue(Kratos.ACCELERATION) - self.assertEqual(acceleration[0], (data[i + offset, 0] + 2) * 3) - self.assertEqual(acceleration[1], (data[i + offset, 1] + 2) * 3) - self.assertEqual(acceleration[2], (data[i + offset, 2] + 2) * 3) - - offset += self.model_part.NumberOfConditions() - for i, element in enumerate(self.model_part.Elements): - acceleration = element.GetValue(Kratos.ACCELERATION) - self.assertEqual(acceleration[0], (data[i + offset, 0] + 2) * 3) - self.assertEqual(acceleration[1], (data[i + offset, 1] + 2) * 3) - self.assertEqual(acceleration[2], (data[i + offset, 2] + 2) * 3) - - # now change the numpy array to check whether we are still referening to data from numpy arraydata - data += 1.0 - KratosOA.CollectiveExpressionIO.Write(collective, [historical(Kratos.ACCELERATION), non_historical(Kratos.ACCELERATION), non_historical(Kratos.ACCELERATION), non_historical(Kratos.ACCELERATION)]) - - # now check for changed values - offset = 0 - for i, node in enumerate(self.model_part.Nodes): - acceleration = node.GetSolutionStepValue(Kratos.ACCELERATION) - self.assertEqual(acceleration[0], (data[i + offset, 0] + 2) * 3) - self.assertEqual(acceleration[1], (data[i + offset, 1] + 2) * 3) - self.assertEqual(acceleration[2], (data[i + offset, 2] + 2) * 3) - - offset += self.model_part.NumberOfNodes() - for i, node in enumerate(self.model_part.Nodes): - acceleration = node.GetValue(Kratos.ACCELERATION) - self.assertEqual(acceleration[0], (data[i + offset, 0] + 2) * 3) - self.assertEqual(acceleration[1], (data[i + offset, 1] + 2) * 3) - self.assertEqual(acceleration[2], (data[i + offset, 2] + 2) * 3) - - offset += self.model_part.NumberOfNodes() - for i, condition in enumerate(self.model_part.Conditions): - acceleration = condition.GetValue(Kratos.ACCELERATION) - self.assertEqual(acceleration[0], (data[i + offset, 0] + 2) * 3) - self.assertEqual(acceleration[1], (data[i + offset, 1] + 2) * 3) - self.assertEqual(acceleration[2], (data[i + offset, 2] + 2) * 3) - - offset += self.model_part.NumberOfConditions() - for i, element in enumerate(self.model_part.Elements): - acceleration = element.GetValue(Kratos.ACCELERATION) - self.assertEqual(acceleration[0], (data[i + offset, 0] + 2) * 3) - self.assertEqual(acceleration[1], (data[i + offset, 1] + 2) * 3) - self.assertEqual(acceleration[2], (data[i + offset, 2] + 2) * 3) - - def test_ReadMoveErrors(self): - a = Kratos.Expression.NodalExpression(self.model_part) - b = Kratos.Expression.NodalExpression(self.model_part) - c = Kratos.Expression.ConditionExpression(self.model_part) - d = Kratos.Expression.ElementExpression(self.model_part) - - collective = KratosOA.CollectiveExpression([a, b, c, d]) - - total_entities = self.model_part.NumberOfNodes() * 4 + self.model_part.NumberOfConditions() * 3 + self.model_part.NumberOfElements() + 1 - - with self.assertRaises(TypeError): - numpy_array = numpy.arange(0, total_entities) - KratosOA.CollectiveExpressionIO.Read(collective, numpy_array, [[3], [], [3], []]) - - with self.assertRaises(TypeError): - numpy_array = numpy.arange(0, total_entities, dtype=numpy.float32) - KratosOA.CollectiveExpressionIO.Read(collective, numpy_array, [[3], [], [3], []]) - - with self.assertRaises(TypeError): - numpy_array = numpy.arange(0, total_entities, dtype=numpy.int32) - KratosOA.CollectiveExpressionIO.Read(collective, numpy_array, [[3], [], [3], []]) - - with self.assertRaises(TypeError): - numpy_array = numpy.arange(0, total_entities, dtype=numpy.int64) - KratosOA.CollectiveExpressionIO.Read(collective, numpy_array, [[3], [], [3], []]) - - with self.assertRaises(TypeError): - numpy_array = numpy.arange(0, total_entities) - KratosOA.CollectiveExpressionIO.Move(collective, numpy_array, [[3], [], [3], []]) - - with self.assertRaises(TypeError): - numpy_array = numpy.arange(0, total_entities, dtype=numpy.float32) - KratosOA.CollectiveExpressionIO.Move(collective, numpy_array, [[3], [], [3], []]) - - with self.assertRaises(TypeError): - numpy_array = numpy.arange(0, total_entities, dtype=numpy.int32) - KratosOA.CollectiveExpressionIO.Move(collective, numpy_array, [[3], [], [3], []]) - - with self.assertRaises(TypeError): - numpy_array = numpy.arange(0, total_entities, dtype=numpy.int64) - KratosOA.CollectiveExpressionIO.Move(collective, numpy_array, [[3], [], [3], []]) - - def test_CollectiveNegation(self): - a = Kratos.Expression.NodalExpression(self.model_part) - b = Kratos.Expression.NodalExpression(self.model_part) - c = Kratos.Expression.ConditionExpression(self.model_part) - d = Kratos.Expression.ElementExpression(self.model_part) - - number_of_nodes = self.model_part.NumberOfNodes() - number_of_conditions = self.model_part.NumberOfConditions() - number_of_elements = self.model_part.NumberOfElements() - d_a = numpy.arange(1, number_of_nodes * 3 + 1, dtype=numpy.float64).reshape((number_of_nodes, 3)) - d_b = numpy.arange(1, number_of_nodes * 4 + 1, dtype=numpy.float64).reshape((number_of_nodes, 2, 2)) - d_c = numpy.arange(1, number_of_conditions * 6 + 1, dtype=numpy.float64).reshape((number_of_conditions, 2, 3)) - d_d = numpy.arange(1, number_of_elements * 9 + 1, dtype=numpy.float64).reshape((number_of_elements, 3, 3)) - - Kratos.Expression.CArrayExpressionIO.Read(a, d_a) - Kratos.Expression.CArrayExpressionIO.Read(b, d_b) - Kratos.Expression.CArrayExpressionIO.Read(c, d_c) - Kratos.Expression.CArrayExpressionIO.Read(d, d_d) - - c_a = KratosOA.CollectiveExpression([a, b, c, d]) - c_b = KratosOA.CollectiveExpression([-a, b * 2, c + 3, d / 2]) - - d = -c_a - self.assertVectorAlmostEqual(c_a.Evaluate(), numpy.concatenate([d_a.flatten(), d_b.flatten(), d_c.flatten(), d_d.flatten()]).flatten()) - self.assertVectorAlmostEqual(c_b.Evaluate(), numpy.concatenate([-d_a.flatten(), d_b.flatten() * 2, d_c.flatten() + 3, d_d.flatten() / 2]).flatten()) - self.assertVectorAlmostEqual(d.Evaluate(), -numpy.concatenate([d_a.flatten(), d_b.flatten(), d_c.flatten(), d_d.flatten()]).flatten()) - - d -= c_b - self.assertVectorAlmostEqual(d.Evaluate(), -numpy.concatenate([d_a.flatten(), d_b.flatten(), d_c.flatten(), d_d.flatten()]).flatten() - numpy.concatenate([-d_a.flatten(), d_b.flatten() * 2, d_c.flatten() + 3, d_d.flatten() / 2]).flatten()) - self.assertVectorAlmostEqual(c_a.Evaluate(), numpy.concatenate([d_a.flatten(), d_b.flatten(), d_c.flatten(), d_d.flatten()]).flatten()) - self.assertVectorAlmostEqual(c_b.Evaluate(), numpy.concatenate([-d_a.flatten(), d_b.flatten() * 2, d_c.flatten() + 3, d_d.flatten() / 2]).flatten()) - - def test_CollectiveAddition(self): - a = Kratos.Expression.NodalExpression(self.model_part) - b = Kratos.Expression.NodalExpression(self.model_part) - c = Kratos.Expression.ConditionExpression(self.model_part) - d = Kratos.Expression.ElementExpression(self.model_part) - - number_of_nodes = self.model_part.NumberOfNodes() - number_of_conditions = self.model_part.NumberOfConditions() - number_of_elements = self.model_part.NumberOfElements() - d_a = numpy.arange(1, number_of_nodes * 3 + 1, dtype=numpy.float64).reshape((number_of_nodes, 3)) - d_b = numpy.arange(1, number_of_nodes * 4 + 1, dtype=numpy.float64).reshape((number_of_nodes, 2, 2)) - d_c = numpy.arange(1, number_of_conditions * 6 + 1, dtype=numpy.float64).reshape((number_of_conditions, 2, 3)) - d_d = numpy.arange(1, number_of_elements * 9 + 1, dtype=numpy.float64).reshape((number_of_elements, 3, 3)) - - Kratos.Expression.CArrayExpressionIO.Read(a, d_a) - Kratos.Expression.CArrayExpressionIO.Read(b, d_b) - Kratos.Expression.CArrayExpressionIO.Read(c, d_c) - Kratos.Expression.CArrayExpressionIO.Read(d, d_d) - - c_a = KratosOA.CollectiveExpression([a, b, c, d]) - c_b = KratosOA.CollectiveExpression([-a, b * 2, c + 3, d / 2]) - - d = c_a.Clone() - d += c_b * 3 - self.assertVectorAlmostEqual(d.Evaluate(), numpy.concatenate([d_a.flatten(), d_b.flatten(), d_c.flatten(), d_d.flatten()]).flatten() + numpy.concatenate([-d_a.flatten(), d_b.flatten() * 2, d_c.flatten() + 3, d_d.flatten() / 2]).flatten() * 3) - self.assertVectorAlmostEqual(c_a.Evaluate(), numpy.concatenate([d_a.flatten(), d_b.flatten(), d_c.flatten(), d_d.flatten()]).flatten()) - self.assertVectorAlmostEqual(c_b.Evaluate(), numpy.concatenate([-d_a.flatten(), d_b.flatten() * 2, d_c.flatten() + 3, d_d.flatten() / 2]).flatten()) - - def test_CollectiveMultiplication(self): - a = Kratos.Expression.NodalExpression(self.model_part) - b = Kratos.Expression.NodalExpression(self.model_part) - c = Kratos.Expression.ConditionExpression(self.model_part) - d = Kratos.Expression.ElementExpression(self.model_part) - - number_of_nodes = self.model_part.NumberOfNodes() - number_of_conditions = self.model_part.NumberOfConditions() - number_of_elements = self.model_part.NumberOfElements() - d_a = numpy.arange(1, number_of_nodes * 3 + 1, dtype=numpy.float64).reshape((number_of_nodes, 3)) - d_b = numpy.arange(1, number_of_nodes * 4 + 1, dtype=numpy.float64).reshape((number_of_nodes, 2, 2)) - d_c = numpy.arange(1, number_of_conditions * 6 + 1, dtype=numpy.float64).reshape((number_of_conditions, 2, 3)) - d_d = numpy.arange(1, number_of_elements * 9 + 1, dtype=numpy.float64).reshape((number_of_elements, 3, 3)) - - Kratos.Expression.CArrayExpressionIO.Read(a, d_a) - Kratos.Expression.CArrayExpressionIO.Read(b, d_b) - Kratos.Expression.CArrayExpressionIO.Read(c, d_c) - Kratos.Expression.CArrayExpressionIO.Read(d, d_d) - - c_a = KratosOA.CollectiveExpression([a, b, c, d]) - c_b = KratosOA.CollectiveExpression([-a, b * 2, c + 3, d / 2]) - - d = c_a.Clone() - d *= c_b - self.assertVectorAlmostEqual(d.Evaluate(), numpy.concatenate([d_a.flatten(), d_b.flatten(), d_c.flatten(), d_d.flatten()]).flatten() * numpy.concatenate([-d_a.flatten(), d_b.flatten() * 2, d_c.flatten() + 3, d_d.flatten() / 2]).flatten()) - self.assertVectorAlmostEqual(c_a.Evaluate(), numpy.concatenate([d_a.flatten(), d_b.flatten(), d_c.flatten(), d_d.flatten()]).flatten()) - self.assertVectorAlmostEqual(c_b.Evaluate(), numpy.concatenate([-d_a.flatten(), d_b.flatten() * 2, d_c.flatten() + 3, d_d.flatten() / 2]).flatten()) - - def test_CollectiveDivision(self): - a = Kratos.Expression.NodalExpression(self.model_part) - b = Kratos.Expression.NodalExpression(self.model_part) - c = Kratos.Expression.ConditionExpression(self.model_part) - d = Kratos.Expression.ElementExpression(self.model_part) - - number_of_nodes = self.model_part.NumberOfNodes() - number_of_conditions = self.model_part.NumberOfConditions() - number_of_elements = self.model_part.NumberOfElements() - d_a = numpy.arange(1, number_of_nodes * 3 + 1, dtype=numpy.float64).reshape((number_of_nodes, 3)) - d_b = numpy.arange(1, number_of_nodes * 4 + 1, dtype=numpy.float64).reshape((number_of_nodes, 2, 2)) - d_c = numpy.arange(1, number_of_conditions * 6 + 1, dtype=numpy.float64).reshape((number_of_conditions, 2, 3)) - d_d = numpy.arange(1, number_of_elements * 9 + 1, dtype=numpy.float64).reshape((number_of_elements, 3, 3)) - - Kratos.Expression.CArrayExpressionIO.Read(a, d_a) - Kratos.Expression.CArrayExpressionIO.Read(b, d_b) - Kratos.Expression.CArrayExpressionIO.Read(c, d_c) - Kratos.Expression.CArrayExpressionIO.Read(d, d_d) - - c_a = KratosOA.CollectiveExpression([a, b, c, d]) - c_b = KratosOA.CollectiveExpression([-a, b * 2, c + 3, d / 2]) - - d = c_a.Clone() - d /= c_b - self.assertVectorAlmostEqual(d.Evaluate(), numpy.concatenate([d_a.flatten(), d_b.flatten(), d_c.flatten(), d_d.flatten()]).flatten() / numpy.concatenate([-d_a.flatten(), d_b.flatten() * 2, d_c.flatten() + 3, d_d.flatten() / 2]).flatten()) - self.assertVectorAlmostEqual(c_a.Evaluate(), numpy.concatenate([d_a.flatten(), d_b.flatten(), d_c.flatten(), d_d.flatten()]).flatten()) - self.assertVectorAlmostEqual(c_b.Evaluate(), numpy.concatenate([-d_a.flatten(), d_b.flatten() * 2, d_c.flatten() + 3, d_d.flatten() / 2]).flatten()) - - -if __name__ == "__main__": - kratos_unittest.main() \ No newline at end of file diff --git a/applications/OptimizationApplication/tests/test_container_expression.py b/applications/OptimizationApplication/tests/test_container_expression.py deleted file mode 100644 index 411eeb1c5d98..000000000000 --- a/applications/OptimizationApplication/tests/test_container_expression.py +++ /dev/null @@ -1,445 +0,0 @@ - -from abc import ABC -from abc import abstractmethod -import KratosMultiphysics as Kratos -import KratosMultiphysics.OptimizationApplication as KratosOA -from KratosMultiphysics.testing.utilities import ReadModelPart - -# Import KratosUnittest -import KratosMultiphysics.KratosUnittest as kratos_unittest - -class TestPropertiesVariableTensorAdaptor(kratos_unittest.TestCase): - @classmethod - def setUpClass(cls): - cls.model = Kratos.Model() - cls.model_part = cls.model.CreateModelPart("test") - cls.model_part.AddNodalSolutionStepVariable(Kratos.DENSITY) - cls.model_part.AddNodalSolutionStepVariable(Kratos.PRESSURE) - cls.model_part.AddNodalSolutionStepVariable(Kratos.ACCELERATION) - cls.model_part.AddNodalSolutionStepVariable(Kratos.VELOCITY) - with kratos_unittest.WorkFolderScope(".", __file__, True): - ReadModelPart("model_part_utils_test/quads", cls.model_part) - - for node in cls.model_part.Nodes: - id = node.Id - node.SetSolutionStepValue(Kratos.VELOCITY, Kratos.Array3([id+3, id+4, id+5])) - node.SetSolutionStepValue(Kratos.PRESSURE, id+3) - node.SetValue(Kratos.PRESSURE, id+3) - node.SetValue(Kratos.VELOCITY, Kratos.Array3([id+3, id+4, id+5])) - - KratosOA.OptimizationUtils.CreateEntitySpecificPropertiesForContainer(cls.model_part, cls.model_part.Conditions, True) - for condition in cls.model_part.Conditions: - id = condition.Id - condition.Properties[Kratos.PRESSURE] = id+400 - condition.Properties[Kratos.VELOCITY] = Kratos.Array3([id+500, id+600, id+700]) - condition.SetValue(Kratos.PRESSURE, id+4) - condition.SetValue(Kratos.VELOCITY, Kratos.Array3([id+5, id+6, id+7])) - - KratosOA.OptimizationUtils.CreateEntitySpecificPropertiesForContainer(cls.model_part, cls.model_part.Elements, True) - for element in cls.model_part.Elements: - id = element.Id - element.Properties[Kratos.PRESSURE] = id+500 - element.Properties[Kratos.VELOCITY] = Kratos.Array3([id+600, id+700, id+800]) - element.SetValue(Kratos.PRESSURE, id+5) - element.SetValue(Kratos.VELOCITY, Kratos.Array3([id+6, id+7, id+8])) - - def test_Check(self): - model = Kratos.Model() - model_part = model.CreateModelPart("test") - model_part.AddNodalSolutionStepVariable(Kratos.DENSITY) - model_part.AddNodalSolutionStepVariable(Kratos.PRESSURE) - model_part.AddNodalSolutionStepVariable(Kratos.ACCELERATION) - model_part.AddNodalSolutionStepVariable(Kratos.VELOCITY) - with kratos_unittest.WorkFolderScope(".", __file__, True): - ReadModelPart("model_part_utils_test/quads", model_part) - - ta = KratosOA.PropertiesVariableTensorAdaptor(model_part.Elements, Kratos.PRESSURE) - with self.assertRaises(RuntimeError): - ta.Check() - - model_part.GetProperties(1)[Kratos.PRESSURE] = 1.0 - with self.assertRaises(RuntimeError): - ta.Check() - - def test_ElementPropertiesScalar(self): - ta = KratosOA.PropertiesVariableTensorAdaptor(self.model_part.Elements, Kratos.PRESSURE) - ta.Check() - ta.CollectData() - - original_ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(ta) - - ta.data *= 2.1 - - for i, element in enumerate(self.model_part.Elements): - self.assertEqual(ta.data[i], element.Properties[Kratos.PRESSURE] * 2.1) - - ta.data *= 4.3 - ta.StoreData() - - for i, element in enumerate(self.model_part.Elements): - self.assertEqual(element.Properties[Kratos.PRESSURE], original_ta.data[i] * 2.1 * 4.3) - - def test_ElementPropertiesVector(self): - ta = KratosOA.PropertiesVariableTensorAdaptor(self.model_part.Elements, Kratos.VELOCITY) - ta.Check() - ta.CollectData() - - original_ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(ta) - - ta.data *= 2.1 - - for i, element in enumerate(self.model_part.Elements): - self.assertVectorAlmostEqual(ta.data[i], element.Properties[Kratos.VELOCITY] * 2.1) - - ta.data *= 4.3 - ta.StoreData() - - for i, element in enumerate(self.model_part.Elements): - self.assertVectorAlmostEqual(element.Properties[Kratos.VELOCITY], original_ta.data[i] * 2.1 * 4.3) - - def test_ConditionPropertiesScalar(self): - ta = KratosOA.PropertiesVariableTensorAdaptor(self.model_part.Conditions, Kratos.PRESSURE) - ta.Check() - ta.CollectData() - - original_ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(ta) - - ta.data *= 2.1 - - for i, condition in enumerate(self.model_part.Conditions): - self.assertEqual(ta.data[i], condition.Properties[Kratos.PRESSURE] * 2.1) - - ta.data *= 4.3 - ta.StoreData() - - for i, condition in enumerate(self.model_part.Conditions): - self.assertEqual(condition.Properties[Kratos.PRESSURE], original_ta.data[i] * 2.1 * 4.3) - - def test_ConditionPropertiesVector(self): - ta = KratosOA.PropertiesVariableTensorAdaptor(self.model_part.Conditions, Kratos.VELOCITY) - ta.Check() - ta.CollectData() - - original_ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(ta) - - ta.data *= 2.1 - - for i, condition in enumerate(self.model_part.Conditions): - self.assertVectorAlmostEqual(ta.data[i], condition.Properties[Kratos.VELOCITY] * 2.1) - - ta.data *= 4.3 - ta.StoreData() - - for i, condition in enumerate(self.model_part.Conditions): - self.assertVectorAlmostEqual(condition.Properties[Kratos.VELOCITY], original_ta.data[i] * 2.1 * 4.3) - -class TestContainerExpression(ABC): - @classmethod - def CreateEntities(cls): - cls.model = Kratos.Model() - cls.model_part = cls.model.CreateModelPart("test") - cls.model_part.AddNodalSolutionStepVariable(Kratos.DENSITY) - cls.model_part.AddNodalSolutionStepVariable(Kratos.PRESSURE) - cls.model_part.AddNodalSolutionStepVariable(Kratos.ACCELERATION) - cls.model_part.AddNodalSolutionStepVariable(Kratos.VELOCITY) - with kratos_unittest.WorkFolderScope(".", __file__, True): - ReadModelPart("model_part_utils_test/quads", cls.model_part) - - for node in cls.model_part.Nodes: - id = node.Id - node.SetSolutionStepValue(Kratos.VELOCITY, Kratos.Array3([id+3, id+4, id+5])) - node.SetSolutionStepValue(Kratos.PRESSURE, id+3) - node.SetValue(Kratos.PRESSURE, id+3) - node.SetValue(Kratos.VELOCITY, Kratos.Array3([id+3, id+4, id+5])) - - KratosOA.OptimizationUtils.CreateEntitySpecificPropertiesForContainer(cls.model_part, cls.model_part.Conditions, True) - for condition in cls.model_part.Conditions: - id = condition.Id - condition.Properties[Kratos.PRESSURE] = id+400 - condition.Properties[Kratos.VELOCITY] = Kratos.Array3([id+500, id+600, id+700]) - condition.SetValue(Kratos.PRESSURE, id+4) - condition.SetValue(Kratos.VELOCITY, Kratos.Array3([id+5, id+6, id+7])) - - KratosOA.OptimizationUtils.CreateEntitySpecificPropertiesForContainer(cls.model_part, cls.model_part.Elements, True) - for element in cls.model_part.Elements: - id = element.Id - element.Properties[Kratos.PRESSURE] = id+500 - element.Properties[Kratos.VELOCITY] = Kratos.Array3([id+600, id+700, id+800]) - element.SetValue(Kratos.PRESSURE, id+5) - element.SetValue(Kratos.VELOCITY, Kratos.Array3([id+6, id+7, id+8])) - - def test_ContainerDataAdd(self): - a = self._GetContainerExpression() - b = self._GetContainerExpression() - - KratosOA.PropertiesVariableExpressionIO.Read(a, Kratos.VELOCITY) - KratosOA.PropertiesVariableExpressionIO.Read(b, Kratos.VELOCITY) - - c = a + b - c += b - - KratosOA.PropertiesVariableExpressionIO.Write(c, Kratos.ACCELERATION) - for node in c.GetContainer(): - self.assertVectorAlmostEqual(self._GetValue(node, Kratos.ACCELERATION), self._GetValue(node, Kratos.VELOCITY) * 3, 12) - - c = a + 100.0 - KratosOA.PropertiesVariableExpressionIO.Write(c, Kratos.ACCELERATION) - for node in c.GetContainer(): - self.assertVectorAlmostEqual(self._GetValue(node, Kratos.ACCELERATION), self._GetValue(node, Kratos.VELOCITY) + Kratos.Array3([100.0, 100.0, 100.0]), 12) - - c += 200.0 - KratosOA.PropertiesVariableExpressionIO.Write(c, Kratos.ACCELERATION) - for node in c.GetContainer(): - self.assertVectorAlmostEqual(self._GetValue(node, Kratos.ACCELERATION), self._GetValue(node, Kratos.VELOCITY) + Kratos.Array3([300.0, 300.0, 300.0]), 12) - - a = self._GetContainerExpression() - b = self._GetContainerExpression() - - KratosOA.PropertiesVariableExpressionIO.Read(a, Kratos.PRESSURE) - KratosOA.PropertiesVariableExpressionIO.Read(b, Kratos.PRESSURE) - - c = a + b - c += b - - KratosOA.PropertiesVariableExpressionIO.Write(c, Kratos.DENSITY) - for node in c.GetContainer(): - self.assertEqual(self._GetValue(node, Kratos.DENSITY), self._GetValue(node, Kratos.PRESSURE) * 3, 12) - - c = a + 100.0 - KratosOA.PropertiesVariableExpressionIO.Write(c, Kratos.DENSITY) - for node in c.GetContainer(): - self.assertEqual(self._GetValue(node, Kratos.DENSITY), self._GetValue(node, Kratos.PRESSURE) + 100.0, 12) - - c += 100.0 - KratosOA.PropertiesVariableExpressionIO.Write(c, Kratos.DENSITY) - for node in c.GetContainer(): - self.assertEqual(self._GetValue(node, Kratos.DENSITY), self._GetValue(node, Kratos.PRESSURE) + 200.0, 12) - - def test_ContainerExpressionMultiplyAndSubstract(self): - a = self._GetContainerExpression() - b = self._GetContainerExpression() - - KratosOA.PropertiesVariableExpressionIO.Read(a, Kratos.VELOCITY) - KratosOA.PropertiesVariableExpressionIO.Read(b, Kratos.VELOCITY) - - c = a * 4 - b - c *= 2 - c -= a - - KratosOA.PropertiesVariableExpressionIO.Write(c, Kratos.ACCELERATION) - for node in c.GetContainer(): - self.assertVectorAlmostEqual(self._GetValue(node, Kratos.ACCELERATION), self._GetValue(node, Kratos.VELOCITY) * 5, 12) - - c = a - 100.0 - KratosOA.PropertiesVariableExpressionIO.Write(c, Kratos.ACCELERATION) - for node in c.GetContainer(): - self.assertVectorAlmostEqual(self._GetValue(node, Kratos.ACCELERATION), self._GetValue(node, Kratos.VELOCITY) - Kratos.Array3([100.0, 100.0, 100.0]), 12) - - c -= 200.0 - KratosOA.PropertiesVariableExpressionIO.Write(c, Kratos.ACCELERATION) - for node in c.GetContainer(): - self.assertVectorAlmostEqual(self._GetValue(node, Kratos.ACCELERATION), self._GetValue(node, Kratos.VELOCITY) - Kratos.Array3([300.0, 300.0, 300.0]), 12) - - a = self._GetContainerExpression() - b = self._GetContainerExpression() - - KratosOA.PropertiesVariableExpressionIO.Read(a, Kratos.PRESSURE) - KratosOA.PropertiesVariableExpressionIO.Read(b, Kratos.PRESSURE) - - c = a * 4 - b - c *= 2 - c -= a - - KratosOA.PropertiesVariableExpressionIO.Write(c, Kratos.DENSITY) - for node in c.GetContainer(): - self.assertEqual(self._GetValue(node, Kratos.DENSITY), self._GetValue(node, Kratos.PRESSURE) * 5, 12) - - c = a - 100.0 - KratosOA.PropertiesVariableExpressionIO.Write(c, Kratos.DENSITY) - for node in c.GetContainer(): - self.assertEqual(self._GetValue(node, Kratos.DENSITY), self._GetValue(node, Kratos.PRESSURE) - 100.0, 12) - - c -= 100.0 - KratosOA.PropertiesVariableExpressionIO.Write(c, Kratos.DENSITY) - for node in c.GetContainer(): - self.assertEqual(self._GetValue(node, Kratos.DENSITY), self._GetValue(node, Kratos.PRESSURE) - 200.0, 12) - - d = c * a - d *= b - KratosOA.PropertiesVariableExpressionIO.Write(d, Kratos.DENSITY) - for node in c.GetContainer(): - self.assertEqual(self._GetValue(node, Kratos.DENSITY), (self._GetValue(node, Kratos.PRESSURE) - 200.0) * self._GetValue(node, Kratos.PRESSURE) ** 2, 12) - - a = self._GetContainerExpression() - KratosOA.PropertiesVariableExpressionIO.Read(a, Kratos.VELOCITY) - - def test_ContainerExpressionDivision(self): - a = self._GetContainerExpression() - KratosOA.PropertiesVariableExpressionIO.Read(a, Kratos.VELOCITY) - - c = a / 2.0 - c /= 2.0 - - KratosOA.PropertiesVariableExpressionIO.Write(c, Kratos.ACCELERATION) - for node in c.GetContainer(): - self.assertVectorAlmostEqual(self._GetValue(node, Kratos.ACCELERATION), self._GetValue(node, Kratos.VELOCITY) / 4, 12) - - a = self._GetContainerExpression() - KratosOA.PropertiesVariableExpressionIO.Read(a, Kratos.PRESSURE) - - c = a / 2.0 - c /= 2.0 - - KratosOA.PropertiesVariableExpressionIO.Write(c, Kratos.DENSITY) - for node in c.GetContainer(): - self.assertEqual(self._GetValue(node, Kratos.DENSITY), self._GetValue(node, Kratos.PRESSURE) / 4, 12) - - d = c / a - d /= (a * 2) - KratosOA.PropertiesVariableExpressionIO.Write(d, Kratos.DENSITY) - for node in c.GetContainer(): - self.assertEqual(self._GetValue(node, Kratos.DENSITY), 0.5 * ((self._GetValue(node, Kratos.PRESSURE) / 4) / self._GetValue(node, Kratos.PRESSURE)) / self._GetValue(node, Kratos.PRESSURE) , 12) - - a = self._GetContainerExpression() - KratosOA.PropertiesVariableExpressionIO.Read(a, Kratos.VELOCITY) - - def test_ContainerExpressionPow(self): - a = self._GetContainerExpression() - KratosOA.PropertiesVariableExpressionIO.Read(a, Kratos.VELOCITY) - - c = a ** 2.0 - c **= 2.0 - - KratosOA.PropertiesVariableExpressionIO.Write(c, Kratos.ACCELERATION) - for node in c.GetContainer(): - ref_value = self._GetValue(node, Kratos.VELOCITY) - self.assertVectorAlmostEqual(self._GetValue(node, Kratos.ACCELERATION), Kratos.Array3([ref_value[0]**4, ref_value[1]**4, ref_value[2]**4]), 12) - - a = self._GetContainerExpression() - KratosOA.PropertiesVariableExpressionIO.Read(a, Kratos.PRESSURE) - - c = a ** 2.0 - c **= 2.0 - - KratosOA.PropertiesVariableExpressionIO.Write(c, Kratos.DENSITY) - for node in c.GetContainer(): - self.assertEqual(self._GetValue(node, Kratos.DENSITY), self._GetValue(node, Kratos.PRESSURE) ** 4, 12) - - def test_ContainerExpressionNeg(self): - a = self._GetContainerExpression() - KratosOA.PropertiesVariableExpressionIO.Read(a, Kratos.VELOCITY) - - c = -a - - KratosOA.PropertiesVariableExpressionIO.Write(c, Kratos.ACCELERATION) - for node in c.GetContainer(): - self.assertVectorAlmostEqual(self._GetValue(node, Kratos.ACCELERATION), self._GetValue(node, Kratos.VELOCITY) * (-1.0), 12) - - a = self._GetContainerExpression() - KratosOA.PropertiesVariableExpressionIO.Read(a, Kratos.PRESSURE) - - c = -a - - KratosOA.PropertiesVariableExpressionIO.Write(c, Kratos.DENSITY) - for node in c.GetContainer(): - self.assertEqual(self._GetValue(node, Kratos.DENSITY), self._GetValue(node, Kratos.PRESSURE) * (-1.0), 12) - - def test_SetDataForContainerVariable(self): - a = self._GetContainerExpression() - Kratos.Expression.LiteralExpressionIO.SetData(a, Kratos.Array3([1, 2, 3])) - KratosOA.PropertiesVariableExpressionIO.Write(a, Kratos.ACCELERATION) - for node in a.GetContainer(): - self.assertVectorAlmostEqual(self._GetValue(node, Kratos.ACCELERATION), Kratos.Array3([1, 2, 3]), 12) - - a = self._GetContainerExpression() - Kratos.Expression.LiteralExpressionIO.SetData(a, 10) - KratosOA.PropertiesVariableExpressionIO.Write(a, Kratos.DENSITY) - for node in a.GetContainer(): - self.assertEqual(self._GetValue(node, Kratos.DENSITY), 10) - - def test_ReadEvaluate(self) -> None: - a = self._GetContainerExpression() - KratosOA.PropertiesVariableExpressionIO.Read(a, Kratos.VELOCITY) - KratosOA.PropertiesVariableExpressionIO.Write(a, Kratos.ACCELERATION) - for node in a.GetContainer(): - self.assertVectorAlmostEqual(self._GetValue(node, Kratos.ACCELERATION), - self._GetValue(node, Kratos.VELOCITY), - 12) - - def test_Clone(self): - a = self._GetContainerExpression() - - KratosOA.PropertiesVariableExpressionIO.Read(a, Kratos.VELOCITY) - - b = a.Clone() - Kratos.Expression.LiteralExpressionIO.SetData(b, Kratos.Array3([10, 11, 12])) - - KratosOA.PropertiesVariableExpressionIO.Write(a, Kratos.ACCELERATION) - for node in a.GetContainer(): - self.assertVectorAlmostEqual(self._GetValue(node, Kratos.ACCELERATION), self._GetValue(node, Kratos.VELOCITY), 12) - - KratosOA.PropertiesVariableExpressionIO.Write(b, Kratos.ACCELERATION) - for node in a.GetContainer(): - self.assertVectorAlmostEqual(self._GetValue(node, Kratos.ACCELERATION), Kratos.Array3([10, 11, 12]), 12) - - a = self._GetContainerExpression() - - KratosOA.PropertiesVariableExpressionIO.Read(a, Kratos.PRESSURE) - - b = a.Clone() - Kratos.Expression.LiteralExpressionIO.SetData(b, 12) - - KratosOA.PropertiesVariableExpressionIO.Write(a, Kratos.DENSITY) - for node in a.GetContainer(): - self.assertEqual(self._GetValue(node, Kratos.DENSITY), self._GetValue(node, Kratos.PRESSURE), 12) - - KratosOA.PropertiesVariableExpressionIO.Write(b, Kratos.DENSITY) - for node in a.GetContainer(): - self.assertEqual(self._GetValue(node, Kratos.DENSITY), 12, 12) - - def test_GetContainer(self): - a = self._GetContainerExpression() - self.assertEqual(self._GetContainer(), a.GetContainer()) - - @abstractmethod - def _GetContainerExpression(self): - pass - - @abstractmethod - def _GetContainer(self): - pass - - @abstractmethod - def _GetValue(self, entity, variable): - pass - -class TestConditionPropertiesExpression(kratos_unittest.TestCase, TestContainerExpression): - @classmethod - def setUpClass(cls): - cls.CreateEntities() - - def _GetContainerExpression(self): - return Kratos.Expression.ConditionExpression(self.model_part) - - def _GetContainer(self): - return self.model_part.GetCommunicator().LocalMesh().Conditions - - def _GetValue(self, entity, variable): - return entity.Properties[variable] - -class TestElementPropertiesExpression(kratos_unittest.TestCase, TestContainerExpression): - @classmethod - def setUpClass(cls): - cls.CreateEntities() - - def _GetContainerExpression(self): - return Kratos.Expression.ElementExpression(self.model_part) - - def _GetContainer(self): - return self.model_part.GetCommunicator().LocalMesh().Elements - - def _GetValue(self, entity, variable): - return entity.Properties[variable] - -if __name__ == "__main__": - kratos_unittest.main() \ No newline at end of file diff --git a/applications/OptimizationApplication/tests/test_container_expression_utils.py b/applications/OptimizationApplication/tests/test_container_expression_utils.py deleted file mode 100644 index dec05c65a28f..000000000000 --- a/applications/OptimizationApplication/tests/test_container_expression_utils.py +++ /dev/null @@ -1,363 +0,0 @@ -import math - -import KratosMultiphysics as Kratos -from KratosMultiphysics import IsDistributedRun -import KratosMultiphysics.OptimizationApplication as KratosOA -import KratosMultiphysics.KratosUnittest as kratos_unittest -from KratosMultiphysics.testing.utilities import ReadModelPart - -class TestContainerExpressionUtils(kratos_unittest.TestCase): - @classmethod - def setUpClass(cls): - cls.model = Kratos.Model() - cls.model_part = cls.model.CreateModelPart("test") - cls.model_part.AddNodalSolutionStepVariable(KratosOA.HELMHOLTZ_VAR_DENSITY) - cls.model_part.AddNodalSolutionStepVariable(Kratos.PRESSURE) - cls.model_part.AddNodalSolutionStepVariable(Kratos.DENSITY) - cls.model_part.AddNodalSolutionStepVariable(Kratos.VELOCITY) - cls.model_part.AddNodalSolutionStepVariable(Kratos.THICKNESS) - with kratos_unittest.WorkFolderScope(".", __file__, True): - ReadModelPart("model_part_utils_test/quads", cls.model_part) - - for node in cls.model_part.Nodes: - id = node.Id - node.SetSolutionStepValue(Kratos.VELOCITY, Kratos.Array3([id+3, id+4, id+5])) - node.SetSolutionStepValue(Kratos.PRESSURE, id+3) - node.SetSolutionStepValue(Kratos.DENSITY, id+4) - node.SetSolutionStepValue(Kratos.THICKNESS, -id) - - def test_ContainerVariableDataEntityMaxNormL2(self): - a = Kratos.Expression.NodalExpression(self.model_part) - - Kratos.Expression.VariableExpressionIO.Read(a, Kratos.PRESSURE, True) - self.assertEqual(KratosOA.ExpressionUtils.EntityMaxNormL2(a), 28) - - Kratos.Expression.VariableExpressionIO.Read(a, Kratos.VELOCITY, True) - self.assertEqual(KratosOA.ExpressionUtils.EntityMaxNormL2(a), math.sqrt(28**2 + 29**2 + 30**2)) - - def test_ContainerVariableDataInnerProduct(self): - a = Kratos.Expression.NodalExpression(self.model_part) - b = Kratos.Expression.NodalExpression(self.model_part) - - Kratos.Expression.VariableExpressionIO.Read(a, Kratos.PRESSURE, True) - Kratos.Expression.VariableExpressionIO.Read(b, Kratos.DENSITY, True) - - self.assertEqual(Kratos.Expression.Utils.InnerProduct(a, b), 8100.0) - - def test_ComputeNumberOfNeighbourConditions(self): - neighbour_conditions = Kratos.Expression.NodalExpression(self.model_part) - KratosOA.ExpressionUtils.ComputeNumberOfNeighbourConditions(neighbour_conditions) - Kratos.Expression.VariableExpressionIO.Write(neighbour_conditions, Kratos.DENSITY, False) - - neighbour_map = { - 2.0: [1, 2, 4, 5, 7, 9, 10, 12, 15, 17, 20, 21, 22, 23, 24, 25], - 0.0: [3, 6, 8, 11, 13, 14, 16, 18, 19] - } - - for node in self.model_part.Nodes: - self.assertTrue(node.Id in neighbour_map[int(node.GetValue(Kratos.DENSITY))]) - - def test_ComputeNumberOfNeighbourElements(self): - neighbour_elements = Kratos.Expression.NodalExpression(self.model_part) - KratosOA.ExpressionUtils.ComputeNumberOfNeighbourElements(neighbour_elements) - Kratos.Expression.VariableExpressionIO.Write(neighbour_elements, Kratos.DENSITY, False) - - neighbour_map = { - 1.0: [1, 9, 22, 25], - 2.0: [2, 4, 5, 7, 10, 12, 15, 17, 20, 21, 23, 24], - 4.0: [3, 6, 8, 11, 13, 14, 16, 18, 19] - } - - for node in self.model_part.Nodes: - self.assertTrue(node.Id in neighbour_map[int(node.GetValue(Kratos.DENSITY))]) - - def test_MapConditionVariableToNodalVariable(self): - communicator: Kratos.Communicator = self.model_part.GetCommunicator() - - for condition in self.model_part.Conditions: - condition.SetValue(Kratos.VELOCITY, Kratos.Array3([condition.Id, condition.Id + 1, condition.Id + 3])) - condition.SetValue(Kratos.PRESSURE, condition.Id + 4) - - condition_container = Kratos.Expression.ConditionExpression(self.model_part) - neighbour_conditions = Kratos.Expression.NodalExpression(self.model_part) - mapped_values = Kratos.Expression.NodalExpression(self.model_part) - - KratosOA.ExpressionUtils.ComputeNumberOfNeighbourConditions(neighbour_conditions) - Kratos.Expression.VariableExpressionIO.Write(neighbour_conditions, Kratos.YOUNG_MODULUS, False) - - Kratos.Expression.VariableExpressionIO.Read(condition_container, Kratos.VELOCITY) - KratosOA.ExpressionUtils.MapContainerVariableToNodalVariable(mapped_values, condition_container, neighbour_conditions) - Kratos.Expression.VariableExpressionIO.Write(mapped_values, Kratos.VELOCITY, False) - - Kratos.VariableUtils().SetNonHistoricalVariableToZero(Kratos.ACCELERATION, self.model_part.Nodes) - for condition in self.model_part.Conditions: - for node in condition.GetGeometry(): - node[Kratos.ACCELERATION] += condition.GetValue(Kratos.VELOCITY) / node.GetValue(Kratos.YOUNG_MODULUS) - - communicator.AssembleNonHistoricalData(Kratos.ACCELERATION) - - for node in self.model_part.Nodes: - self.assertVectorAlmostEqual(node[Kratos.ACCELERATION], node[Kratos.VELOCITY]) - - Kratos.Expression.VariableExpressionIO.Read(condition_container, Kratos.PRESSURE) - KratosOA.ExpressionUtils.MapContainerVariableToNodalVariable(mapped_values, condition_container, neighbour_conditions) - Kratos.Expression.VariableExpressionIO.Write(mapped_values, Kratos.PRESSURE, False) - - Kratos.VariableUtils().SetNonHistoricalVariableToZero(Kratos.DENSITY, self.model_part.Nodes) - for condition in self.model_part.Conditions: - for node in condition.GetGeometry(): - node[Kratos.DENSITY] += condition.GetValue(Kratos.PRESSURE) / node.GetValue(Kratos.YOUNG_MODULUS) - - communicator.AssembleNonHistoricalData(Kratos.DENSITY) - - for node in self.model_part.Nodes: - self.assertAlmostEqual(node[Kratos.DENSITY], node[Kratos.PRESSURE], 9) - - def test_MapElementVariableToNodalVariable(self): - communicator: Kratos.Communicator = self.model_part.GetCommunicator() - - for element in self.model_part.Elements: - element.SetValue(Kratos.VELOCITY, Kratos.Array3([element.Id, element.Id + 1, element.Id + 3])) - element.SetValue(Kratos.PRESSURE, element.Id + 4) - - element_container = Kratos.Expression.ElementExpression(self.model_part) - neighbour_elements = Kratos.Expression.NodalExpression(self.model_part) - mapped_values = Kratos.Expression.NodalExpression(self.model_part) - - KratosOA.ExpressionUtils.ComputeNumberOfNeighbourElements(neighbour_elements) - Kratos.Expression.VariableExpressionIO.Write(neighbour_elements, Kratos.YOUNG_MODULUS, False) - - Kratos.Expression.VariableExpressionIO.Read(element_container, Kratos.VELOCITY) - KratosOA.ExpressionUtils.MapContainerVariableToNodalVariable(mapped_values, element_container, neighbour_elements) - Kratos.Expression.VariableExpressionIO.Write(mapped_values, Kratos.VELOCITY, False) - - Kratos.VariableUtils().SetNonHistoricalVariableToZero(Kratos.ACCELERATION, self.model_part.Nodes) - for element in self.model_part.Elements: - for node in element.GetGeometry(): - node[Kratos.ACCELERATION] += element.GetValue(Kratos.VELOCITY) / node.GetValue(Kratos.YOUNG_MODULUS) - - communicator.AssembleNonHistoricalData(Kratos.ACCELERATION) - - for node in self.model_part.Nodes: - self.assertVectorAlmostEqual(node[Kratos.ACCELERATION], node[Kratos.VELOCITY]) - - Kratos.Expression.VariableExpressionIO.Read(element_container, Kratos.PRESSURE) - KratosOA.ExpressionUtils.MapContainerVariableToNodalVariable(mapped_values, element_container, neighbour_elements) - Kratos.Expression.VariableExpressionIO.Write(mapped_values, Kratos.PRESSURE, False) - - Kratos.VariableUtils().SetNonHistoricalVariableToZero(Kratos.DENSITY, self.model_part.Nodes) - for element in self.model_part.Elements: - for node in element.GetGeometry(): - node[Kratos.DENSITY] += element.GetValue(Kratos.PRESSURE) / node.GetValue(Kratos.YOUNG_MODULUS) - - communicator.AssembleNonHistoricalData(Kratos.DENSITY) - - for node in self.model_part.Nodes: - self.assertEqual(node[Kratos.DENSITY], node[Kratos.PRESSURE]) - - def test_MapNodalVariableToConditionVariable(self): - for node in self.model_part.Nodes: - node.SetValue(Kratos.VELOCITY, Kratos.Array3([node.Id, node.Id + 1, node.Id + 3])) - node.SetValue(Kratos.PRESSURE, node.Id + 4) - - nodal_container = Kratos.Expression.NodalExpression(self.model_part) - mapped_value = Kratos.Expression.ConditionExpression(self.model_part) - - Kratos.Expression.VariableExpressionIO.Read(nodal_container, Kratos.VELOCITY, False) - KratosOA.ExpressionUtils.MapNodalVariableToContainerVariable(mapped_value, nodal_container) - Kratos.Expression.VariableExpressionIO.Write(mapped_value, Kratos.ACCELERATION) - - for condition in self.model_part.Conditions: - v = Kratos.Array3([0, 0, 0]) - for node in condition.GetGeometry(): - v += node.GetValue(Kratos.VELOCITY) - self.assertVectorAlmostEqual(v / 2.0, condition.GetValue(Kratos.ACCELERATION)) - - Kratos.Expression.VariableExpressionIO.Read(nodal_container, Kratos.PRESSURE, False) - KratosOA.ExpressionUtils.MapNodalVariableToContainerVariable(mapped_value, nodal_container) - Kratos.Expression.VariableExpressionIO.Write(mapped_value, Kratos.DENSITY) - - for condition in self.model_part.Conditions: - v = 0.0 - for node in condition.GetGeometry(): - v += node.GetValue(Kratos.PRESSURE) - self.assertEqual(v / 2.0, condition.GetValue(Kratos.DENSITY)) - - def test_ProductWithEntityMatrix(self): - if (IsDistributedRun()): - self.skipTest("Skipping since ProductWithEntityMatrix does not support MPI yet.") - - number_of_nodes = self.model_part.NumberOfNodes() - - a = Kratos.Expression.NodalExpression(self.model_part) - Kratos.Expression.VariableExpressionIO.Read(a, Kratos.PRESSURE, True) - - m = Kratos.Matrix(number_of_nodes, number_of_nodes) - for i in range(number_of_nodes): - for j in range(number_of_nodes): - m[i, j] = (i + 1) * (j + 1) - - b = Kratos.Expression.NodalExpression(self.model_part) - KratosOA.ExpressionUtils.ProductWithEntityMatrix(b, m, a) - Kratos.Expression.VariableExpressionIO.Write(b, Kratos.DENSITY, True) - - for i, node_b in enumerate(b.GetContainer()): - v = 0 - for j, node_a in enumerate(a.GetContainer()): - v += m[i, j] * node_a.GetSolutionStepValue(Kratos.PRESSURE) - self.assertEqual(v, node_b.GetSolutionStepValue(Kratos.DENSITY)) - - def test_ProductWithEntityMatrixSparse(self): - if (IsDistributedRun()): - self.skipTest("Skipping since ProductWithEntityMatrix does not support MPI yet.") - - number_of_nodes = self.model_part.NumberOfNodes() - - a = Kratos.Expression.NodalExpression(self.model_part) - Kratos.Expression.VariableExpressionIO.Read(a, Kratos.PRESSURE, True) - - dense_m = Kratos.Matrix(number_of_nodes, number_of_nodes) - for i in range(number_of_nodes): - for j in range(number_of_nodes): - dense_m[i, j] = int((i + 1) * (j + 1) % 10) - - # now add values to the sparse matrix - sparse_m = Kratos.CompressedMatrix(number_of_nodes, number_of_nodes) - for i in range(number_of_nodes): - for j in range(number_of_nodes): - if dense_m[i, j] != 0.0: - sparse_m[i, j] = dense_m[i, j] - - dense_b = Kratos.Expression.NodalExpression(self.model_part) - KratosOA.ExpressionUtils.ProductWithEntityMatrix(dense_b, dense_m, a) - - sparse_b = Kratos.Expression.NodalExpression(self.model_part) - KratosOA.ExpressionUtils.ProductWithEntityMatrix(sparse_b, sparse_m, a) - - self.assertEqual(Kratos.Expression.Utils.InnerProduct(dense_b - sparse_b, dense_b - sparse_b), 0) - - def test_Transpose(self): - matrix_size = 10 - - # first build the normal matrix - dense_m = Kratos.Matrix( - [ - [5, 0, 0, 2, 0, 0, 0, 0, 0], - [0, 0, 3, 2, 3, 0, 0, 0, 0], - [0, 2, 0, 2, 0, 2, 0, 6, 0], - [0, 0, 0, 2, 0, 4, 0, 5, 0], - [0, 0, 2, 0, 0, 2, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 3, 3], - [0, 2, 0, 0, 3, 0, 4, 0, 0], - [3, 0, 0, 2, 0, 0, 0, 2, 0], - [9, 0, 0, 0, 0, 7, 0, 7, 0], - [0, 0, 7, 2, 0, 0, 0, 0, 0] - ] - ) - transpose_dense_m = Kratos.Matrix() - KratosOA.ExpressionUtils.Transpose(transpose_dense_m, dense_m) - for i in range(dense_m.Size1()): - for j in range(dense_m.Size2()): - self.assertEqual(transpose_dense_m[j, i], dense_m[i, j]) - - # now add values to the sparse matrix - sparse_m = Kratos.CompressedMatrix(matrix_size, matrix_size) - for i in range(dense_m.Size1()): - for j in range(dense_m.Size2()): - if dense_m[i, j] != 0.0: - sparse_m[i, j] = dense_m[i, j] - - transpose_sparse_m = Kratos.CompressedMatrix() - KratosOA.ExpressionUtils.Transpose(transpose_sparse_m, sparse_m) - for i in range(dense_m.Size1()): - for j in range(dense_m.Size2()): - self.assertEqual(transpose_sparse_m[j, i], dense_m[i, j]) - - def test_ComputeVariableDataHolderProductWithEntityMatrix(self): - for node in self.model_part.Nodes: - node.SetValue(Kratos.PRESSURE, node.Id + 1) - node.SetSolutionStepValue(KratosOA.HELMHOLTZ_VAR_DENSITY, node.Id + 1) - - nodal_values = Kratos.Expression.NodalExpression(self.model_part) - Kratos.Expression.VariableExpressionIO.Read(nodal_values, Kratos.PRESSURE, False) - - output_values = Kratos.Expression.NodalExpression(self.model_part) - KratosOA.ExpressionUtils.ComputeNodalVariableProductWithEntityMatrix(output_values, nodal_values, KratosOA.HELMHOLTZ_MASS_MATRIX, self.model_part.Elements) - - # analytical calculation - Kratos.VariableUtils().SetNonHistoricalVariableToZero(Kratos.DENSITY, self.model_part.Nodes) - element: Kratos.Element - for element in self.model_part.Elements: - v_in = Kratos.Vector(4) - for i, node in enumerate(element.GetGeometry()): - v_in[i] = node.GetSolutionStepValue(KratosOA.HELMHOLTZ_VAR_DENSITY) - - m = element.Calculate(KratosOA.HELMHOLTZ_MASS_MATRIX, self.model_part.ProcessInfo) - v_out = m * v_in - - for i, node in enumerate(element.GetGeometry()): - node.SetValue(Kratos.DENSITY, node.GetValue(Kratos.DENSITY) + v_out[i]) - - self.model_part.GetCommunicator().AssembleNonHistoricalData(Kratos.DENSITY) - - analytical_values = Kratos.Expression.NodalExpression(self.model_part) - Kratos.Expression.VariableExpressionIO.Read(analytical_values, Kratos.DENSITY, False) - - self.assertEqual(Kratos.Expression.Utils.NormL2(analytical_values - output_values), 0.0) - - def test_Scopes(self): - a = Kratos.Expression.NodalExpression(self.model_part) - b = Kratos.Expression.NodalExpression(self.model_part) - - Kratos.Expression.VariableExpressionIO.Read(a, Kratos.VELOCITY, True) - Kratos.Expression.VariableExpressionIO.Read(b, Kratos.PRESSURE, True) - - def func(a): - c = a * 2 - d = c * 3 - return d - - c = func(a) - d = func(b) - - e = c.Clone() - Kratos.Expression.VariableExpressionIO.Write(e, Kratos.ACCELERATION, False) - f = d.Clone() - Kratos.Expression.VariableExpressionIO.Write(f, Kratos.DENSITY, False) - - for node in self.model_part.Nodes: - self.assertVectorAlmostEqual(node.GetSolutionStepValue(Kratos.VELOCITY) * 6, node.GetValue(Kratos.ACCELERATION)) - self.assertEqual(node.GetSolutionStepValue(Kratos.PRESSURE) * 6, node.GetValue(Kratos.DENSITY)) - - def test_CollectiveExpressionsNormInf(self): - a = Kratos.Expression.NodalExpression(self.model_part) - b = Kratos.Expression.ElementExpression(self.model_part) - - Kratos.Expression.VariableExpressionIO.Read(a, Kratos.VELOCITY, True) - KratosOA.PropertiesVariableExpressionIO.Read(b, Kratos.PRESSURE) - - collective_1 = KratosOA.CollectiveExpression([a, b]) - self.assertEqual(KratosOA.ExpressionUtils.NormInf(collective_1), max(Kratos.Expression.Utils.NormInf(a), Kratos.Expression.Utils.NormInf(b))) - - def test_CollectiveExpressionsNormL2(self): - a = Kratos.Expression.NodalExpression(self.model_part) - b = Kratos.Expression.ElementExpression(self.model_part) - - Kratos.Expression.VariableExpressionIO.Read(a, Kratos.VELOCITY, True) - KratosOA.PropertiesVariableExpressionIO.Read(b, Kratos.PRESSURE) - - collective_1 = KratosOA.CollectiveExpression([a, b]) - self.assertEqual(KratosOA.ExpressionUtils.NormL2(collective_1), math.sqrt(Kratos.Expression.Utils.NormL2(a)**2 + Kratos.Expression.Utils.NormL2(b)**2)) - - def test_CollectiveExpressionsInnerProduct(self): - a = Kratos.Expression.NodalExpression(self.model_part) - b = Kratos.Expression.ElementExpression(self.model_part) - - Kratos.Expression.VariableExpressionIO.Read(a, Kratos.VELOCITY, True) - KratosOA.PropertiesVariableExpressionIO.Read(b, Kratos.PRESSURE) - - collective_1 = KratosOA.CollectiveExpression([a, b]) - self.assertEqual(KratosOA.ExpressionUtils.InnerProduct(collective_1, collective_1), Kratos.Expression.Utils.InnerProduct(a, a) + Kratos.Expression.Utils.InnerProduct(b, b)) - -if __name__ == "__main__": - kratos_unittest.main() \ No newline at end of file From 87ae858dc4689c4da4d078579ac54c2dcb41ceea Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Wed, 4 Feb 2026 15:45:56 +0100 Subject: [PATCH 040/116] update discrete value response --- ...screte_value_residual_response_function.py | 73 +++++++++---------- ...screte_value_residual_response_function.py | 15 ++-- 2 files changed, 41 insertions(+), 47 deletions(-) diff --git a/applications/OptimizationApplication/python_scripts/responses/discrete_value_residual_response_function.py b/applications/OptimizationApplication/python_scripts/responses/discrete_value_residual_response_function.py index 63e78226c25c..eeff3f114aad 100644 --- a/applications/OptimizationApplication/python_scripts/responses/discrete_value_residual_response_function.py +++ b/applications/OptimizationApplication/python_scripts/responses/discrete_value_residual_response_function.py @@ -1,3 +1,4 @@ +import numpy from typing import Optional import KratosMultiphysics as Kratos @@ -41,21 +42,18 @@ def __init__(self, name: str, model: Kratos.Model, parameters: Kratos.Parameters raise RuntimeError(f"Unsupported residual_type = \"{self.residual_type}\" requested. Followings are supported:\n\texact\n\tlogarithm") container_type = parameters["container_type"].GetString() - if container_type == "node_historical" or container_type == "node_non_historical": - self.expression_getter = lambda model_part : Kratos.Expression.NodalExpression(model_part) - self.expression_reader = lambda exp: Kratos.Expression.VariableExpressionIO.Read(exp, self.variable, container_type == "node_historical") - elif container_type == "condition" or container_type == "condition_properties": - self.expression_getter = lambda model_part : Kratos.Expression.ConditionExpression(model_part) - if container_type == "condition": - self.expression_reader = lambda exp: Kratos.Expression.VariableExpressionIO.Read(exp, self.variable) - else: - self.expression_reader = lambda exp: KratosOA.PropertiesVariableExpressionIO(exp, self.variable) - elif container_type == "element" or container_type == "element_properties": - self.expression_getter = lambda model_part : Kratos.Expression.ElementExpression(model_part) - if container_type == "element": - self.expression_reader = lambda exp: Kratos.Expression.VariableExpressionIO.Read(exp, self.variable) - else: - self.expression_reader = lambda exp: KratosOA.PropertiesVariableExpressionIO(exp, self.variable) + if container_type == "node_historical": + self.ta_getter = lambda model_part: Kratos.TensorAdaptors.HistoricalVariableTensorAdaptor(model_part.Nodes, self.variable) + elif container_type == "node_non_historical": + self.ta_getter = lambda model_part : Kratos.TensorAdaptors.VariableTensorAdaptor(model_part.Nodes, self.variable) + elif container_type == "condition": + self.ta_getter = lambda model_part : Kratos.TensorAdaptors.VariableTensorAdaptor(model_part.Conditions, self.variable) + elif container_type == "condition_properties": + self.ta_getter = lambda model_part : KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(model_part.Conditions, self.variable) + elif container_type == "element": + self.ta_getter = lambda model_part : Kratos.TensorAdaptors.VariableTensorAdaptor(model_part.Elements, self.variable) + elif container_type == "element_properties": + self.ta_getter = lambda model_part : KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(model_part.Elements, self.variable) else: raise RuntimeError(f"Unsupported container_type = \"{container_type}\" requested. Followings are supported:\n\tnode_historical\n\tnode_non_historical\n\tcondition\n\tcondition_properties\n\telement\n\telement_properties") @@ -84,50 +82,49 @@ def Finalize(self) -> None: pass def CalculateValue(self) -> float: - exp = self.expression_getter(self.model_part) - self.expression_reader(exp) + ta = self.ta_getter(self.model_part) + ta.CollectData() - resultant = exp.Clone() + resultant = Kratos.TensorAdaptors.DoubleTensorAdaptor(ta) if self.residual_type == "exact": - Kratos.Expression.LiteralExpressionIO.SetData(resultant, 1.0) + resultant.data[:] = 1.0 elif self.residual_type == "logarithm": - Kratos.Expression.LiteralExpressionIO.SetData(resultant, 0.0) + resultant.data[:] = 0.0 for value in self.list_of_discrete_values: if self.residual_type == "exact": - resultant *= (exp - value) ** 2 + resultant.data *= (ta.data - value) ** 2 elif self.residual_type == "logarithm": - resultant += Kratos.Expression.Utils.Log((exp - value) ** 2) + resultant.data += numpy.log((ta.data[:] - value) ** 2) - return Kratos.Expression.Utils.Sum(resultant) + return numpy.sum(resultant.data) - def CalculateGradient(self, physical_variable_collective_expressions: 'dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]') -> None: - values = self.expression_getter(self.model_part) - self.expression_reader(values) + def CalculateGradient(self, physical_variable_combined_tensor_adaptor: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]') -> None: + values = self.ta_getter(self.model_part) + values.CollectData() # calculate the gradients - for physical_variable, collective_expression in physical_variable_collective_expressions.items(): + for physical_variable, cta in physical_variable_combined_tensor_adaptor.items(): if physical_variable == self.variable: - expressions = collective_expression.GetContainerExpressions() + tas = cta.GetTensorAdaptors() # initialize the current expression - for exp in expressions: - Kratos.Expression.LiteralExpressionIO.SetData(exp, 0.0) + for ta in tas: + ta.data[:] = 0.0 - for exp in expressions: + for ta in tas: for i, value_i in enumerate(self.list_of_discrete_values): if self.residual_type == "exact": - partial_gradient_exp = exp.Clone() - Kratos.Expression.LiteralExpressionIO.SetData(partial_gradient_exp, 1.0) + partial_gradient_ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(ta) + partial_gradient_ta.data[:] = 1.0 for j, value_j in enumerate(self.list_of_discrete_values): if i == j: - partial_gradient_exp *= (values - value_j) * 2.0 + partial_gradient_ta.data *= (values.data[:] - value_j) * 2.0 else: - partial_gradient_exp *= (values - value_j) ** 2 - exp.SetExpression(exp.GetExpression() + partial_gradient_exp.GetExpression()) + partial_gradient_ta.data *= (values.data[:] - value_j) ** 2 + ta.data[:] += partial_gradient_ta.data elif self.residual_type == "logarithm": - exp.SetExpression(exp.GetExpression() + (((values - value_i) ** (-2)) * (values - value_i) * 2.0).GetExpression()) - exp.SetExpression(Kratos.Expression.Utils.Collapse(exp).GetExpression()) + ta.data[:] += (((values.data - value_i) ** (-2)) * (values.data - value_i) * 2.0) else: raise RuntimeError(f"Unsupported sensitivity w.r.t. {physical_variable.Name()} requested. Followings are supported sensitivity variables:\n\t{self.variable.Name()}") diff --git a/applications/OptimizationApplication/tests/responses_tests/test_discrete_value_residual_response_function.py b/applications/OptimizationApplication/tests/responses_tests/test_discrete_value_residual_response_function.py index 622603dbd41e..651f4ebf0be1 100644 --- a/applications/OptimizationApplication/tests/responses_tests/test_discrete_value_residual_response_function.py +++ b/applications/OptimizationApplication/tests/responses_tests/test_discrete_value_residual_response_function.py @@ -41,16 +41,15 @@ def test_CalculateValue(self): def test_CalculateGradient(self): ref_value = self.response_function.CalculateValue() - analytical_gradient = Kratos.Expression.NodalExpression(self.model_part) - self.response_function.CalculateGradient({Kratos.PRESSURE: KratosOA.CollectiveExpression([analytical_gradient])}) - analytical_gradient = analytical_gradient.Evaluate() + analytical_gradient = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, Kratos.PRESSURE) + self.response_function.CalculateGradient({Kratos.PRESSURE: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([analytical_gradient])}) delta = 1e-9 for i, node in enumerate(self.model_part.Nodes): node.SetValue(Kratos.PRESSURE, node.GetValue(Kratos.PRESSURE) + delta) fd_gradient = (self.response_function.CalculateValue() - ref_value) / delta node.SetValue(Kratos.PRESSURE, node.GetValue(Kratos.PRESSURE) - delta) - self.assertAlmostEqual(fd_gradient, analytical_gradient[i], 5) + self.assertAlmostEqual(fd_gradient, analytical_gradient.data[i], 5) class TestDiscreteValueResidualResponseFunctionLogarithm(kratos_unittest.TestCase): @classmethod @@ -87,17 +86,15 @@ def test_CalculateValue(self): def test_CalculateGradient(self): ref_value = self.response_function.CalculateValue() - analytical_gradient = Kratos.Expression.NodalExpression(self.model_part) - self.response_function.CalculateGradient({Kratos.PRESSURE: KratosOA.CollectiveExpression([analytical_gradient])}) - analytical_gradient = analytical_gradient.Evaluate() + analytical_gradient = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, Kratos.PRESSURE) + self.response_function.CalculateGradient({Kratos.PRESSURE: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([analytical_gradient])}) delta = 1e-8 for i, node in enumerate(self.model_part.Nodes): node.SetValue(Kratos.PRESSURE, node.GetValue(Kratos.PRESSURE) + delta) fd_gradient = (self.response_function.CalculateValue() - ref_value) / delta node.SetValue(Kratos.PRESSURE, node.GetValue(Kratos.PRESSURE) - delta) - self.assertAlmostEqual(fd_gradient, analytical_gradient[i], 5) + self.assertAlmostEqual(fd_gradient, analytical_gradient.data[i], 5) if __name__ == "__main__": - Kratos.Tester.SetVerbosity(Kratos.Tester.Verbosity.PROGRESS) # TESTS_OUTPUTS kratos_unittest.main() \ No newline at end of file From 843cbf709e94b10f1b464a49280a7116ffc0075b Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Wed, 4 Feb 2026 17:19:21 +0100 Subject: [PATCH 041/116] update mass resp --- .../responses/mass_response_function.py | 42 ++------------ .../test_mass_response_function.py | 56 +++++++++---------- 2 files changed, 33 insertions(+), 65 deletions(-) diff --git a/applications/OptimizationApplication/python_scripts/responses/mass_response_function.py b/applications/OptimizationApplication/python_scripts/responses/mass_response_function.py index 407a807661af..1b8eecfca726 100644 --- a/applications/OptimizationApplication/python_scripts/responses/mass_response_function.py +++ b/applications/OptimizationApplication/python_scripts/responses/mass_response_function.py @@ -6,7 +6,6 @@ from KratosMultiphysics.OptimizationApplication.responses.response_function import SupportedSensitivityFieldVariableTypes from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes from KratosMultiphysics.OptimizationApplication.utilities.model_part_utilities import ModelPartOperation -from KratosMultiphysics.OptimizationApplication.utilities.model_part_utilities import ModelPartUtilities def Factory(model: Kratos.Model, parameters: Kratos.Parameters, _) -> ResponseFunction: if not parameters.Has("name"): @@ -60,46 +59,15 @@ def GetInfluencingModelPart(self) -> Kratos.ModelPart: def CalculateValue(self) -> float: return KratosOA.ResponseUtils.MassResponseUtils.CalculateValue(self.model_part) - def CalculateGradient(self, physical_variable_collective_expressions: 'dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]') -> None: - # first merge all the model parts - merged_model_part_map = ModelPartUtilities.GetMergedMap(physical_variable_collective_expressions, False) - - # now get the intersected model parts - intersected_model_part_map = ModelPartUtilities.GetIntersectedMap(self.model_part, merged_model_part_map, False) - - # TODO: Remove this block once everything is updated to TensorAdaptors - # ========================================================= - physical_variable_combined_tensor_adaptors: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]' = {} - for physical_variable, collective_expression in physical_variable_collective_expressions.items(): - ta_list = [] - for ce in collective_expression.GetContainerExpressions(): - if isinstance(physical_variable, Kratos.DoubleVariable): - shape = Kratos.DenseVectorUnsignedInt([len(ce.GetContainer())]) - elif isinstance(physical_variable, Kratos.Array1DVariable3): - shape = Kratos.DenseVectorUnsignedInt([len(ce.GetContainer()), 3]) - else: - raise RuntimeError("Unsupported type") - - ta_list.append(Kratos.TensorAdaptors.DoubleTensorAdaptor(ce.GetContainer(), Kratos.DoubleNDData(shape), copy=False)) - cta = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(ta_list, False, False) - physical_variable_combined_tensor_adaptors[physical_variable] = cta - # ========================================================= - + def CalculateGradient(self, physical_variable_combined_tensor_adaptor: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]') -> None: # calculate the gradients - for physical_variable, merged_model_part in merged_model_part_map.items(): + for physical_variable, cta in physical_variable_combined_tensor_adaptor.items(): KratosOA.ResponseUtils.MassResponseUtils.CalculateGradient( physical_variable, - merged_model_part, - intersected_model_part_map[physical_variable], - physical_variable_combined_tensor_adaptors[physical_variable], + self.model_part, + self.model_part, + cta, self.perturbation_size) - # TODO: Remove this block once everything is updated to TensorAdaptors - # ========================================================= - for physical_variable, collective_expression in physical_variable_collective_expressions.items(): - for i, ce in enumerate(collective_expression.GetContainerExpressions()): - Kratos.Expression.CArrayExpressionIO.Read(ce, physical_variable_combined_tensor_adaptors[physical_variable].GetTensorAdaptors()[i].data) - # ========================================================= - def __str__(self) -> str: return f"Response [type = {self.__class__.__name__}, name = {self.GetName()}, model part name = {self.model_part.FullName()}]" \ No newline at end of file diff --git a/applications/OptimizationApplication/tests/responses_tests/test_mass_response_function.py b/applications/OptimizationApplication/tests/responses_tests/test_mass_response_function.py index 6209429e4bca..54ecdfa30809 100644 --- a/applications/OptimizationApplication/tests/responses_tests/test_mass_response_function.py +++ b/applications/OptimizationApplication/tests/responses_tests/test_mass_response_function.py @@ -31,7 +31,7 @@ def setUpClass(cls): cls.response_function.Check() cls.ref_value = cls.response_function.CalculateValue() - def _CheckSensitivity(self, response_function: MassResponseFunction, entities, sensitivity_method, update_method, container_expression_data, delta, precision): + def _CheckSensitivity(self, response_function: MassResponseFunction, entities, sensitivity_method, update_method, ta_data, delta, precision): ref_value = response_function.CalculateValue() list_of_sensitivities = [] for entity in entities: @@ -44,7 +44,7 @@ def _CheckSensitivity(self, response_function: MassResponseFunction, entities, s list_of_sensitivities.append(v) list_of_sensitivities = numpy.array(list_of_sensitivities) - self.assertVectorAlmostEqual(list_of_sensitivities, container_expression_data, precision) + self.assertVectorAlmostEqual(list_of_sensitivities, ta_data, precision) def _UpdateProperties(self, variable, entity, delta): entity.Properties[variable] += delta @@ -81,7 +81,7 @@ def test_CalculateValue(self): self.assertAlmostEqual(self.ref_value, 126, 12) def test_CalculateShapeSensitivity(self): - sensitivity = KratosOA.CollectiveExpression([Kratos.Expression.NodalExpression(self.model_part)]) + sensitivity = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, KratosOA.SHAPE)], perform_collect_data_recursively=False, perform_store_data_recursively=False) self.response_function.CalculateGradient({KratosOA.SHAPE: sensitivity}) # calculate nodal shape sensitivities @@ -90,7 +90,7 @@ def test_CalculateShapeSensitivity(self): self.model_part.Nodes, lambda x: x.GetValue(Kratos.SHAPE_SENSITIVITY_X), lambda x, y: self._UpdateNodalPositions(0, x, y), - sensitivity.GetContainerExpressions()[0].Evaluate()[:, 0], + sensitivity.GetTensorAdaptors()[0].data[:, 0], 1e-6, 4) @@ -99,12 +99,12 @@ def test_CalculateShapeSensitivity(self): self.model_part.Nodes, lambda x: x.GetValue(Kratos.SHAPE_SENSITIVITY_Y), lambda x, y: self._UpdateNodalPositions(1, x, y), - sensitivity.GetContainerExpressions()[0].Evaluate()[:, 1], + sensitivity.GetTensorAdaptors()[0].data[:, 1], 1e-6, 4) def test_CalculateDensitySensitivity(self): - sensitivity = KratosOA.CollectiveExpression([Kratos.Expression.ElementExpression(self.model_part)]) + sensitivity = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Elements, Kratos.DENSITY)], perform_collect_data_recursively=False, perform_store_data_recursively=False) self.response_function.CalculateGradient({Kratos.DENSITY: sensitivity}) # calculate element density sensitivity @@ -113,12 +113,12 @@ def test_CalculateDensitySensitivity(self): self.model_part.Elements, lambda x: x.Properties[KratosOA.DENSITY_SENSITIVITY], lambda x, y: self._UpdateProperties(Kratos.DENSITY, x, y), - sensitivity.GetContainerExpressions()[0].Evaluate(), + sensitivity.GetTensorAdaptors()[0].data, 1e-6, 6) def test_CalculateCrossAreaSensitivity(self): - sensitivity = KratosOA.CollectiveExpression([Kratos.Expression.ElementExpression(self.model_part)]) + sensitivity = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Elements, KratosOA.CROSS_AREA)], perform_collect_data_recursively=False, perform_store_data_recursively=False) self.response_function.CalculateGradient({KratosOA.CROSS_AREA: sensitivity}) # calculate element cross area sensitivity @@ -127,7 +127,7 @@ def test_CalculateCrossAreaSensitivity(self): self.model_part.Elements, lambda x: x.Properties[KratosOA.CROSS_AREA_SENSITIVITY], lambda x, y: self._UpdateProperties(KratosOA.CROSS_AREA, x, y), - sensitivity.GetContainerExpressions()[0].Evaluate(), + sensitivity.GetTensorAdaptors()[0].data, 1e-6, 6) @@ -159,7 +159,7 @@ def test_CalculateValue(self): self.assertAlmostEqual(self.ref_value, 15, 12) def test_CalculateShapeSensitivity(self): - sensitivity = KratosOA.CollectiveExpression([Kratos.Expression.NodalExpression(self.model_part)]) + sensitivity = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, KratosOA.SHAPE)], perform_collect_data_recursively=False, perform_store_data_recursively=False) self.response_function.CalculateGradient({KratosOA.SHAPE: sensitivity}) # calculate nodal shape sensitivities @@ -168,7 +168,7 @@ def test_CalculateShapeSensitivity(self): self.model_part.Nodes, lambda x: x.GetValue(Kratos.SHAPE_SENSITIVITY_X), lambda x, y: self._UpdateNodalPositions(0, x, y), - sensitivity.GetContainerExpressions()[0].Evaluate()[:, 0], + sensitivity.GetTensorAdaptors()[0].data[:, 0], 1e-6, 4) @@ -177,12 +177,12 @@ def test_CalculateShapeSensitivity(self): self.model_part.Nodes, lambda x: x.GetValue(Kratos.SHAPE_SENSITIVITY_Y), lambda x, y: self._UpdateNodalPositions(1, x, y), - sensitivity.GetContainerExpressions()[0].Evaluate()[:, 1], + sensitivity.GetTensorAdaptors()[0].data[:, 1], 1e-6, 4) def test_CalculateDensitySensitivity(self): - sensitivity = KratosOA.CollectiveExpression([Kratos.Expression.ElementExpression(self.model_part)]) + sensitivity = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Elements, Kratos.DENSITY)], perform_collect_data_recursively=False, perform_store_data_recursively=False) self.response_function.CalculateGradient({Kratos.DENSITY: sensitivity}) # calculate element density sensitivity @@ -191,12 +191,12 @@ def test_CalculateDensitySensitivity(self): self.model_part.Elements, lambda x: x.Properties[KratosOA.DENSITY_SENSITIVITY], lambda x, y: self._UpdateProperties(Kratos.DENSITY, x, y), - sensitivity.GetContainerExpressions()[0].Evaluate(), + sensitivity.GetTensorAdaptors()[0].data, 1e-6, 6) def test_CalculateThicknessSensitivity(self): - sensitivity = KratosOA.CollectiveExpression([Kratos.Expression.ElementExpression(self.model_part)]) + sensitivity = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Elements, Kratos.THICKNESS)], perform_collect_data_recursively=False, perform_store_data_recursively=False) self.response_function.CalculateGradient({Kratos.THICKNESS: sensitivity}) # calculate element cross area sensitivity @@ -205,7 +205,7 @@ def test_CalculateThicknessSensitivity(self): self.model_part.Elements, lambda x: x.Properties[KratosOA.THICKNESS_SENSITIVITY], lambda x, y: self._UpdateProperties(Kratos.THICKNESS, x, y), - sensitivity.GetContainerExpressions()[0].Evaluate(), + sensitivity.GetTensorAdaptors()[0].data, 1e-7, 6) @@ -239,7 +239,7 @@ def test_CalculateValue(self): self.assertAlmostEqual(self.ref_value, v, 12) def test_CalculateShapeSensitivity(self): - sensitivity = KratosOA.CollectiveExpression([Kratos.Expression.NodalExpression(self.model_part)]) + sensitivity = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, KratosOA.SHAPE)], perform_collect_data_recursively=False, perform_store_data_recursively=False) self.response_function.CalculateGradient({KratosOA.SHAPE: sensitivity}) # calculate nodal shape sensitivities @@ -248,7 +248,7 @@ def test_CalculateShapeSensitivity(self): self.model_part.Nodes, lambda x: x.GetValue(Kratos.SHAPE_SENSITIVITY_X), lambda x, y: self._UpdateNodalPositions(0, x, y), - sensitivity.GetContainerExpressions()[0].Evaluate()[:, 0], + sensitivity.GetTensorAdaptors()[0].data[:, 0], 1e-6, 4) @@ -257,7 +257,7 @@ def test_CalculateShapeSensitivity(self): self.model_part.Nodes, lambda x: x.GetValue(Kratos.SHAPE_SENSITIVITY_Y), lambda x, y: self._UpdateNodalPositions(1, x, y), - sensitivity.GetContainerExpressions()[0].Evaluate()[:, 1], + sensitivity.GetTensorAdaptors()[0].data[:, 1], 1e-6, 4) @@ -266,12 +266,12 @@ def test_CalculateShapeSensitivity(self): self.model_part.Nodes, lambda x: x.GetValue(Kratos.SHAPE_SENSITIVITY_Z), lambda x, y: self._UpdateNodalPositions(2, x, y), - sensitivity.GetContainerExpressions()[0].Evaluate()[:, 2], + sensitivity.GetTensorAdaptors()[0].data[:, 2], 1e-6, 4) def test_CalculateDensitySensitivity(self): - sensitivity = KratosOA.CollectiveExpression([Kratos.Expression.ElementExpression(self.model_part)]) + sensitivity = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Elements, Kratos.DENSITY)], perform_collect_data_recursively=False, perform_store_data_recursively=False) self.response_function.CalculateGradient({Kratos.DENSITY: sensitivity}) # calculate element density sensitivity @@ -280,7 +280,7 @@ def test_CalculateDensitySensitivity(self): self.model_part.Elements, lambda x: x.Properties[KratosOA.DENSITY_SENSITIVITY], lambda x, y: self._UpdateProperties(Kratos.DENSITY, x, y), - sensitivity.GetContainerExpressions()[0].Evaluate(), + sensitivity.GetTensorAdaptors()[0].data, 1e-6, 6) @@ -310,7 +310,7 @@ def test_CalculateValue(self): self.assertAlmostEqual(self.ref_value, v, 12) def test_CalculateShapeSensitivity(self): - sensitivity = KratosOA.CollectiveExpression([Kratos.Expression.NodalExpression(self.model_part)]) + sensitivity = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, KratosOA.SHAPE)], perform_collect_data_recursively=False, perform_store_data_recursively=False) self.response_function.CalculateGradient({KratosOA.SHAPE: sensitivity}) # calculate nodal shape sensitivities @@ -319,7 +319,7 @@ def test_CalculateShapeSensitivity(self): self.model_part.Nodes, lambda x: x.GetValue(Kratos.SHAPE_SENSITIVITY_X), lambda x, y: self._UpdateNodalPositions(0, x, y), - sensitivity.GetContainerExpressions()[0].Evaluate()[:, 0], + sensitivity.GetTensorAdaptors()[0].data[:, 0], 1e-6, 4) @@ -328,7 +328,7 @@ def test_CalculateShapeSensitivity(self): self.model_part.Nodes, lambda x: x.GetValue(Kratos.SHAPE_SENSITIVITY_Y), lambda x, y: self._UpdateNodalPositions(1, x, y), - sensitivity.GetContainerExpressions()[0].Evaluate()[:, 1], + sensitivity.GetTensorAdaptors()[0].data[:, 1], 1e-6, 4) @@ -337,12 +337,12 @@ def test_CalculateShapeSensitivity(self): self.model_part.Nodes, lambda x: x.GetValue(Kratos.SHAPE_SENSITIVITY_Z), lambda x, y: self._UpdateNodalPositions(2, x, y), - sensitivity.GetContainerExpressions()[0].Evaluate()[:, 2], + sensitivity.GetTensorAdaptors()[0].data[:, 2], 1e-6, 4) def test_CalculateDensitySensitivity(self): - sensitivity = KratosOA.CollectiveExpression([Kratos.Expression.ElementExpression(self.model_part)]) + sensitivity = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Elements, Kratos.DENSITY)], perform_collect_data_recursively=False, perform_store_data_recursively=False) self.response_function.CalculateGradient({Kratos.DENSITY: sensitivity}) # calculate element density sensitivity @@ -351,7 +351,7 @@ def test_CalculateDensitySensitivity(self): self.model_part.Elements, lambda x: x.Properties[KratosOA.DENSITY_SENSITIVITY], lambda x, y: self._UpdateProperties(Kratos.DENSITY, x, y), - sensitivity.GetContainerExpressions()[0].Evaluate(), + sensitivity.GetTensorAdaptors()[0].data, 1e-6, 6) From 1561ebebd67c365b18dc8748bc63700b8bc9a629 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Thu, 5 Feb 2026 06:11:00 +0100 Subject: [PATCH 042/116] fix recursive CollectData calls --- .../response/mass_response_utils.cpp | 6 +++++- .../test_mass_response_function.py | 20 +++++++++---------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/applications/OptimizationApplication/custom_utilities/response/mass_response_utils.cpp b/applications/OptimizationApplication/custom_utilities/response/mass_response_utils.cpp index a8dd4c95592e..6a0e2b777c14 100644 --- a/applications/OptimizationApplication/custom_utilities/response/mass_response_utils.cpp +++ b/applications/OptimizationApplication/custom_utilities/response/mass_response_utils.cpp @@ -125,6 +125,9 @@ void MassResponseUtils::CalculateGradient( { KRATOS_TRY + // make a copy of combined tensor adaptor, but sharing the internal NDData + CombinedTensorAdaptor temp_cta(rCombinedTensorAdaptor, false, false, false); + std::visit([&](auto pVariable) { if (*pVariable == DENSITY) { // clears the existing values @@ -187,7 +190,8 @@ void MassResponseUtils::CalculateGradient( }, rPhysicalVariable); // update the combined tensor adaptor flat vector. - rCombinedTensorAdaptor.CollectData(); + // below will never call the CollectData recursively. + temp_cta.CollectData(); KRATOS_CATCH(""); } diff --git a/applications/OptimizationApplication/tests/responses_tests/test_mass_response_function.py b/applications/OptimizationApplication/tests/responses_tests/test_mass_response_function.py index 54ecdfa30809..c246732168e1 100644 --- a/applications/OptimizationApplication/tests/responses_tests/test_mass_response_function.py +++ b/applications/OptimizationApplication/tests/responses_tests/test_mass_response_function.py @@ -81,7 +81,7 @@ def test_CalculateValue(self): self.assertAlmostEqual(self.ref_value, 126, 12) def test_CalculateShapeSensitivity(self): - sensitivity = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, KratosOA.SHAPE)], perform_collect_data_recursively=False, perform_store_data_recursively=False) + sensitivity = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, KratosOA.SHAPE)]) self.response_function.CalculateGradient({KratosOA.SHAPE: sensitivity}) # calculate nodal shape sensitivities @@ -104,7 +104,7 @@ def test_CalculateShapeSensitivity(self): 4) def test_CalculateDensitySensitivity(self): - sensitivity = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Elements, Kratos.DENSITY)], perform_collect_data_recursively=False, perform_store_data_recursively=False) + sensitivity = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Elements, Kratos.DENSITY)]) self.response_function.CalculateGradient({Kratos.DENSITY: sensitivity}) # calculate element density sensitivity @@ -118,7 +118,7 @@ def test_CalculateDensitySensitivity(self): 6) def test_CalculateCrossAreaSensitivity(self): - sensitivity = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Elements, KratosOA.CROSS_AREA)], perform_collect_data_recursively=False, perform_store_data_recursively=False) + sensitivity = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Elements, KratosOA.CROSS_AREA)]) self.response_function.CalculateGradient({KratosOA.CROSS_AREA: sensitivity}) # calculate element cross area sensitivity @@ -159,7 +159,7 @@ def test_CalculateValue(self): self.assertAlmostEqual(self.ref_value, 15, 12) def test_CalculateShapeSensitivity(self): - sensitivity = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, KratosOA.SHAPE)], perform_collect_data_recursively=False, perform_store_data_recursively=False) + sensitivity = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, KratosOA.SHAPE)]) self.response_function.CalculateGradient({KratosOA.SHAPE: sensitivity}) # calculate nodal shape sensitivities @@ -182,7 +182,7 @@ def test_CalculateShapeSensitivity(self): 4) def test_CalculateDensitySensitivity(self): - sensitivity = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Elements, Kratos.DENSITY)], perform_collect_data_recursively=False, perform_store_data_recursively=False) + sensitivity = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Elements, Kratos.DENSITY)]) self.response_function.CalculateGradient({Kratos.DENSITY: sensitivity}) # calculate element density sensitivity @@ -196,7 +196,7 @@ def test_CalculateDensitySensitivity(self): 6) def test_CalculateThicknessSensitivity(self): - sensitivity = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Elements, Kratos.THICKNESS)], perform_collect_data_recursively=False, perform_store_data_recursively=False) + sensitivity = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Elements, Kratos.THICKNESS)]) self.response_function.CalculateGradient({Kratos.THICKNESS: sensitivity}) # calculate element cross area sensitivity @@ -239,7 +239,7 @@ def test_CalculateValue(self): self.assertAlmostEqual(self.ref_value, v, 12) def test_CalculateShapeSensitivity(self): - sensitivity = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, KratosOA.SHAPE)], perform_collect_data_recursively=False, perform_store_data_recursively=False) + sensitivity = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, KratosOA.SHAPE)]) self.response_function.CalculateGradient({KratosOA.SHAPE: sensitivity}) # calculate nodal shape sensitivities @@ -271,7 +271,7 @@ def test_CalculateShapeSensitivity(self): 4) def test_CalculateDensitySensitivity(self): - sensitivity = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Elements, Kratos.DENSITY)], perform_collect_data_recursively=False, perform_store_data_recursively=False) + sensitivity = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Elements, Kratos.DENSITY)]) self.response_function.CalculateGradient({Kratos.DENSITY: sensitivity}) # calculate element density sensitivity @@ -310,7 +310,7 @@ def test_CalculateValue(self): self.assertAlmostEqual(self.ref_value, v, 12) def test_CalculateShapeSensitivity(self): - sensitivity = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, KratosOA.SHAPE)], perform_collect_data_recursively=False, perform_store_data_recursively=False) + sensitivity = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, KratosOA.SHAPE)]) self.response_function.CalculateGradient({KratosOA.SHAPE: sensitivity}) # calculate nodal shape sensitivities @@ -342,7 +342,7 @@ def test_CalculateShapeSensitivity(self): 4) def test_CalculateDensitySensitivity(self): - sensitivity = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Elements, Kratos.DENSITY)], perform_collect_data_recursively=False, perform_store_data_recursively=False) + sensitivity = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Elements, Kratos.DENSITY)]) self.response_function.CalculateGradient({Kratos.DENSITY: sensitivity}) # calculate element density sensitivity From 5c44707b417fee6ee482569faab25a61a20953d9 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Thu, 5 Feb 2026 06:21:09 +0100 Subject: [PATCH 043/116] update linear strain energy resp --- .../linear_strain_energy_response_utils.cpp | 5 ++- .../linear_strain_energy_response_function.py | 42 +++---------------- ..._linear_strain_energy_response_function.py | 20 ++++----- 3 files changed, 19 insertions(+), 48 deletions(-) diff --git a/applications/OptimizationApplication/custom_utilities/response/linear_strain_energy_response_utils.cpp b/applications/OptimizationApplication/custom_utilities/response/linear_strain_energy_response_utils.cpp index 16cc73b1a2d1..dd94e2b67862 100644 --- a/applications/OptimizationApplication/custom_utilities/response/linear_strain_energy_response_utils.cpp +++ b/applications/OptimizationApplication/custom_utilities/response/linear_strain_energy_response_utils.cpp @@ -90,6 +90,8 @@ void LinearStrainEnergyResponseUtils::CalculateGradient( { KRATOS_TRY + CombinedTensorAdaptor temp_cta(rCombinedTensorAdaptor, false, false, false); + std::visit([&](auto pVariable) { if (*pVariable == YOUNG_MODULUS) { block_for_each(rGradientRequiredModelPart.Elements(), [](auto& rElement) { rElement.GetProperties().SetValue(YOUNG_MODULUS_SENSITIVITY, 0.0); }); @@ -140,7 +142,8 @@ void LinearStrainEnergyResponseUtils::CalculateGradient( }, rPhysicalVariable); // update the combined tensor adaptor flat vector. - rCombinedTensorAdaptor.CollectData(); + // below will never call the CollectData recursively. + temp_cta.CollectData(); KRATOS_CATCH(""); } diff --git a/applications/OptimizationApplication/python_scripts/responses/linear_strain_energy_response_function.py b/applications/OptimizationApplication/python_scripts/responses/linear_strain_energy_response_function.py index e9759c488553..28e8a574f350 100644 --- a/applications/OptimizationApplication/python_scripts/responses/linear_strain_energy_response_function.py +++ b/applications/OptimizationApplication/python_scripts/responses/linear_strain_energy_response_function.py @@ -7,7 +7,6 @@ from KratosMultiphysics.OptimizationApplication.responses.response_function import ResponseFunction from KratosMultiphysics.OptimizationApplication.responses.response_function import SupportedSensitivityFieldVariableTypes from KratosMultiphysics.OptimizationApplication.utilities.model_part_utilities import ModelPartOperation -from KratosMultiphysics.OptimizationApplication.utilities.model_part_utilities import ModelPartUtilities def Factory(model: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem) -> ResponseFunction: if not parameters.Has("name"): @@ -60,46 +59,15 @@ def CalculateValue(self) -> float: self.primal_analysis_execution_policy_decorator.Execute() return KratosOA.ResponseUtils.LinearStrainEnergyResponseUtils.CalculateValue(self.model_part) - def CalculateGradient(self, physical_variable_collective_expressions: 'dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]') -> None: - # first merge all the model parts - merged_model_part_map = ModelPartUtilities.GetMergedMap(physical_variable_collective_expressions, False) - - # now get the intersected model parts - intersected_model_part_map = ModelPartUtilities.GetIntersectedMap(self.model_part, merged_model_part_map, True) - - # TODO: Remove this block once everything is updated to TensorAdaptors - # ========================================================= - physical_variable_combined_tensor_adaptors: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]' = {} - for physical_variable, collective_expression in physical_variable_collective_expressions.items(): - ta_list = [] - for ce in collective_expression.GetContainerExpressions(): - if isinstance(physical_variable, Kratos.DoubleVariable): - shape = Kratos.DenseVectorUnsignedInt([len(ce.GetContainer())]) - elif isinstance(physical_variable, Kratos.Array1DVariable3): - shape = Kratos.DenseVectorUnsignedInt([len(ce.GetContainer()), 3]) - else: - raise RuntimeError("Unsupported type") - - ta_list.append(Kratos.TensorAdaptors.DoubleTensorAdaptor(ce.GetContainer(), Kratos.DoubleNDData(shape), copy=False)) - cta = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(ta_list, False, False) - physical_variable_combined_tensor_adaptors[physical_variable] = cta - # ========================================================= - + def CalculateGradient(self, physical_variable_combined_tensor_adaptor: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]') -> None: # calculate the gradients - for physical_variable, merged_model_part in merged_model_part_map.items(): + for physical_variable, cta in physical_variable_combined_tensor_adaptor.items(): KratosOA.ResponseUtils.LinearStrainEnergyResponseUtils.CalculateGradient( physical_variable, - merged_model_part, - intersected_model_part_map[physical_variable], - physical_variable_combined_tensor_adaptors[physical_variable], + self.GetInfluencingModelPart(), + self.GetInfluencingModelPart(), + cta, self.perturbation_size) - # TODO: Remove this block once everything is updated to TensorAdaptors - # ========================================================= - for physical_variable, collective_expression in physical_variable_collective_expressions.items(): - for i, ce in enumerate(collective_expression.GetContainerExpressions()): - Kratos.Expression.CArrayExpressionIO.Read(ce, physical_variable_combined_tensor_adaptors[physical_variable].GetTensorAdaptors()[i].data) - # ========================================================= - def __str__(self) -> str: return f"Response [type = {self.__class__.__name__}, name = {self.GetName()}, model part name = {self.model_part.FullName()}]" \ No newline at end of file diff --git a/applications/OptimizationApplication/tests/responses_tests/test_linear_strain_energy_response_function.py b/applications/OptimizationApplication/tests/responses_tests/test_linear_strain_energy_response_function.py index beaf3db34231..36b6c328caa4 100644 --- a/applications/OptimizationApplication/tests/responses_tests/test_linear_strain_energy_response_function.py +++ b/applications/OptimizationApplication/tests/responses_tests/test_linear_strain_energy_response_function.py @@ -67,7 +67,7 @@ def tearDownClass(cls): with kratos_unittest.WorkFolderScope("linear_strain_energy_test", __file__): DeleteFileIfExisting("Structure.time") - def _CheckSensitivity(self, response_function, entities, sensitivity_method, update_method, container_expression_data, delta, rel_tol, abs_tol): + def _CheckSensitivity(self, response_function, entities, sensitivity_method, update_method, tensor_adaptor_data, delta, rel_tol, abs_tol): list_of_sensitivities = [] for entity in entities: adjoint_sensitivity = sensitivity_method(entity) @@ -82,7 +82,7 @@ def _CheckSensitivity(self, response_function, entities, sensitivity_method, upd list_of_sensitivities.append(adjoint_sensitivity) list_of_sensitivities = numpy.array(list_of_sensitivities) - self.assertTrue(all(numpy.isclose(list_of_sensitivities, container_expression_data, rtol=rel_tol, atol=abs_tol))) + self.assertTrue(all(numpy.isclose(list_of_sensitivities, tensor_adaptor_data, rtol=rel_tol, atol=abs_tol))) def _UpdateProperties(self, variable, entity, delta): entity.Properties[variable] += delta @@ -102,7 +102,7 @@ def test_CalculateValue(self): self.assertAlmostEqual(self.ref_value, 71515947.17480606, 6) def test_CalculateYoungModulusSensitivity(self): - sensitivity = KratosOA.CollectiveExpression([Kratos.Expression.ElementExpression(self.model_part)]) + sensitivity = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Elements, Kratos.YOUNG_MODULUS)]) self.response_function.CalculateGradient({Kratos.YOUNG_MODULUS: sensitivity}) # calculate element density sensitivity @@ -111,13 +111,13 @@ def test_CalculateYoungModulusSensitivity(self): self.model_part.Elements, lambda x: x.Properties[KratosOA.YOUNG_MODULUS_SENSITIVITY], lambda x, y: self._UpdateProperties(Kratos.YOUNG_MODULUS, x, y), - sensitivity.GetContainerExpressions()[0].Evaluate(), + sensitivity.GetTensorAdaptors()[0].data, 1e-7, 1e-6, 1e-5) def test_CalculatePoissonRatioSensitivity(self): - sensitivity = KratosOA.CollectiveExpression([Kratos.Expression.ElementExpression(self.model_part)]) + sensitivity = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Elements, Kratos.POISSON_RATIO)]) self.response_function.CalculateGradient({Kratos.POISSON_RATIO: sensitivity}) # calculate element density sensitivity @@ -126,13 +126,13 @@ def test_CalculatePoissonRatioSensitivity(self): self.model_part.Elements, lambda x: x.Properties[KratosOA.POISSON_RATIO_SENSITIVITY], lambda x, y: self._UpdateProperties(Kratos.POISSON_RATIO, x, y), - sensitivity.GetContainerExpressions()[0].Evaluate(), + sensitivity.GetTensorAdaptors()[0].data, 1e-7, 1e-4, 1e-5) def test_CalculateShapeSensitivity(self): - sensitivity = KratosOA.CollectiveExpression([Kratos.Expression.NodalExpression(self.model_part)]) + sensitivity = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, KratosOA.SHAPE)]) self.response_function.CalculateGradient({KratosOA.SHAPE: sensitivity}) # calculate nodal shape sensitivities @@ -141,7 +141,7 @@ def test_CalculateShapeSensitivity(self): self.model_part.Nodes, lambda x: x.GetValue(Kratos.SHAPE_SENSITIVITY_X), lambda x, y: self._UpdateNodalPositions(0, x, y), - sensitivity.GetContainerExpressions()[0].Evaluate()[:, 0], + sensitivity.GetTensorAdaptors()[0].data[:, 0], 1e-6, 1e-4, 1e-5) @@ -151,7 +151,7 @@ def test_CalculateShapeSensitivity(self): self.model_part.Nodes, lambda x: x.GetValue(Kratos.SHAPE_SENSITIVITY_Y), lambda x, y: self._UpdateNodalPositions(1, x, y), - sensitivity.GetContainerExpressions()[0].Evaluate()[:, 1], + sensitivity.GetTensorAdaptors()[0].data[:, 1], 1e-6, 1e-4, 1e-5) @@ -161,7 +161,7 @@ def test_CalculateShapeSensitivity(self): self.model_part.Nodes, lambda x: x.GetValue(Kratos.SHAPE_SENSITIVITY_Z), lambda x, y: self._UpdateNodalPositions(2, x, y), - sensitivity.GetContainerExpressions()[0].Evaluate()[:, 2], + sensitivity.GetTensorAdaptors()[0].data[:, 2], 1e-6, 1e-4, 1e-5) From 97c0a2a05345f0e73ce4f45bbaaded19afc19225 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Thu, 5 Feb 2026 06:23:05 +0100 Subject: [PATCH 044/116] minor --- .../custom_utilities/filtering/explicit_filter_utils.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/applications/OptimizationApplication/custom_utilities/filtering/explicit_filter_utils.cpp b/applications/OptimizationApplication/custom_utilities/filtering/explicit_filter_utils.cpp index e4d8b6713f9c..78762b42f791 100644 --- a/applications/OptimizationApplication/custom_utilities/filtering/explicit_filter_utils.cpp +++ b/applications/OptimizationApplication/custom_utilities/filtering/explicit_filter_utils.cpp @@ -34,7 +34,7 @@ namespace Kratos { namespace ExplicitFilterUtilsHelperUtilities { template -void GetNodalDomainSizeExpression( +void GetNodalDomainSizes( std::vector& rNodalDomainSizes, const TContainerType& rContainer, const ModelPart::NodesContainerType& rNodes) @@ -236,9 +236,9 @@ void ExplicitFilterUtils::ExplicitFilterUtils::Update() const IndexType number_of_elements = r_elements.size(); if (number_of_elements > 0) { - ExplicitFilterUtilsHelperUtilities::GetNodalDomainSizeExpression(mNodalDomainSizes, r_elements, r_nodes); + ExplicitFilterUtilsHelperUtilities::GetNodalDomainSizes(mNodalDomainSizes, r_elements, r_nodes); } else if (number_of_conditions > 0) { - ExplicitFilterUtilsHelperUtilities::GetNodalDomainSizeExpression(mNodalDomainSizes, r_conditions, r_nodes); + ExplicitFilterUtilsHelperUtilities::GetNodalDomainSizes(mNodalDomainSizes, r_conditions, r_nodes); } else { KRATOS_ERROR << "Nodal mapping requires atleast either conditions or elements to be present in " << mrModelPart.FullName() << ".\n"; From a9d0d27c7974495b15849dda0b252d71c7c8a5f4 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Thu, 5 Feb 2026 09:07:43 +0100 Subject: [PATCH 045/116] string changes --- .../add_custom_filters_to_python.cpp | 2 +- .../filtering/explicit_damping.h | 2 +- .../filtering/explicit_filter_utils.cpp | 34 +++++++++---------- .../filtering/explicit_filter_utils.h | 6 ++-- .../linear_strain_energy_response_utils.cpp | 2 +- .../response/mass_response_utils.cpp | 2 +- 6 files changed, 24 insertions(+), 24 deletions(-) diff --git a/applications/OptimizationApplication/custom_python/add_custom_filters_to_python.cpp b/applications/OptimizationApplication/custom_python/add_custom_filters_to_python.cpp index bb60b0f3baf2..24c4f499d4dd 100644 --- a/applications/OptimizationApplication/custom_python/add_custom_filters_to_python.cpp +++ b/applications/OptimizationApplication/custom_python/add_custom_filters_to_python.cpp @@ -62,7 +62,7 @@ void AddExplicitDamping( using explicit_damping_type = ExplicitDamping; py::class_(m, (rSuffix + "ExplicitDamping").c_str()) - .def("SetRadius", &explicit_damping_type::SetRadius, py::arg("radius_expression")) + .def("SetRadius", &explicit_damping_type::SetRadius, py::arg("radius_tensor_adaptor")) .def("GetRadius", &explicit_damping_type::GetRadius) .def("GetStride", &explicit_damping_type::GetStride) .def("GetDampedModelParts", &explicit_damping_type::GetDampedModelParts) diff --git a/applications/OptimizationApplication/custom_utilities/filtering/explicit_damping.h b/applications/OptimizationApplication/custom_utilities/filtering/explicit_damping.h index 661f3b6bbbe6..b3c256c56b1a 100644 --- a/applications/OptimizationApplication/custom_utilities/filtering/explicit_damping.h +++ b/applications/OptimizationApplication/custom_utilities/filtering/explicit_damping.h @@ -66,7 +66,7 @@ class KRATOS_API(OPTIMIZATION_APPLICATION) ExplicitDamping } /** - * @brief Get the used damping radius expression + * @brief Get the used damping radius tensor adaptor */ virtual TensorAdaptor::Pointer GetRadius() const { diff --git a/applications/OptimizationApplication/custom_utilities/filtering/explicit_filter_utils.cpp b/applications/OptimizationApplication/custom_utilities/filtering/explicit_filter_utils.cpp index 78762b42f791..9c39ee9123f2 100644 --- a/applications/OptimizationApplication/custom_utilities/filtering/explicit_filter_utils.cpp +++ b/applications/OptimizationApplication/custom_utilities/filtering/explicit_filter_utils.cpp @@ -171,21 +171,21 @@ void ExplicitFilterUtils::SetRadius(TensorAdaptor::Point if (std::holds_alternative(pTensorAdaptor->GetContainer())) { const auto& r_container = *(std::get(pTensorAdaptor->GetContainer())); KRATOS_ERROR_IF_NOT(&r_container == &mrModelPart.Nodes() || &r_container == &mrModelPart.GetCommunicator().LocalMesh().Nodes()) - << "Filter radius container expression model part and filter model part mismatch." + << "Filter radius tensor adaptor container and filter model part mismatch." << "\n\tFilter = " << *this - << "\n\tContainerExpression = " << *pTensorAdaptor; + << "\n\tTensorAdaptor = " << *pTensorAdaptor; } else if (std::holds_alternative(pTensorAdaptor->GetContainer())) { const auto& r_container = *(std::get(pTensorAdaptor->GetContainer())); KRATOS_ERROR_IF_NOT(&r_container == &mrModelPart.Conditions()) - << "Filter radius container expression model part and filter model part mismatch." + << "Filter radius tensor adaptor container and filter model part mismatch." << "\n\tFilter = " << *this - << "\n\tContainerExpression = " << *pTensorAdaptor; + << "\n\tTensorAdaptor = " << *pTensorAdaptor; } else if (std::holds_alternative(pTensorAdaptor->GetContainer())) { const auto& r_container = *(std::get(pTensorAdaptor->GetContainer())); KRATOS_ERROR_IF_NOT(&r_container == &mrModelPart.Elements()) - << "Filter radius container expression model part and filter model part mismatch." + << "Filter radius tensor adaptor container and filter model part mismatch." << "\n\tFilter = " << *this - << "\n\tContainerExpression = " << *pTensorAdaptor; + << "\n\tTensorAdaptor = " << *pTensorAdaptor; } else { KRATOS_ERROR << "Unsupported container type is found in the tensor adaptor. Only supports nodal, condition or elemental tensor adaptors [ tensor adaptor = " << *pTensorAdaptor << " ].\n"; @@ -255,28 +255,28 @@ template void ExplicitFilterUtils::CheckField(const TensorAdaptor& rTensorAdaptor) const { KRATOS_ERROR_IF(mpFilterRadiusTensorAdaptor.get() == nullptr) - << "The filter radius container expression not set. " + << "The filter radius tensor adaptor not set. " << "Please set it using SetRadius method.\n\t Filter = " << *this; if (std::holds_alternative(rTensorAdaptor.GetContainer())) { const auto& r_container = *(std::get(rTensorAdaptor.GetContainer())); KRATOS_ERROR_IF_NOT(&r_container == &mrModelPart.Nodes() || &r_container == &mrModelPart.GetCommunicator().LocalMesh().Nodes()) - << "Filter radius container expression model part and filter model part mismatch." + << "Filter radius tensor adaptor container and filter model part mismatch." << "\n\tFilter = " << *this - << "\n\tContainerExpression = " << rTensorAdaptor; + << "\n\tTensorAdaptor = " << rTensorAdaptor; } else if (std::holds_alternative(rTensorAdaptor.GetContainer())) { const auto& r_container = *(std::get(rTensorAdaptor.GetContainer())); KRATOS_ERROR_IF_NOT(&r_container == &mrModelPart.Conditions()) - << "Filter radius container expression model part and filter model part mismatch." + << "Filter radius tensor adaptor container and filter model part mismatch." << "\n\tFilter = " << *this - << "\n\tContainerExpression = " << rTensorAdaptor; + << "\n\tTensorAdaptor = " << rTensorAdaptor; } else if (std::holds_alternative(rTensorAdaptor.GetContainer())) { const auto& r_container = *(std::get(rTensorAdaptor.GetContainer())); KRATOS_ERROR_IF_NOT(&r_container == &mrModelPart.Elements()) - << "Filter radius container expression model part and filter model part mismatch." + << "Filter radius tensor adaptor container and filter model part mismatch." << "\n\tFilter = " << *this - << "\n\tContainerExpression = " << rTensorAdaptor; + << "\n\tTensorAdaptor = " << rTensorAdaptor; } else { KRATOS_ERROR << "Unsupported container type is found in the tensor adaptor. Only supports nodal, condition or elemental tensor adaptors [ tensor adaptor = " << rTensorAdaptor << " ].\n"; @@ -304,8 +304,8 @@ TensorAdaptor::Pointer ExplicitFilterUtils::GenericForwa const auto& r_filter_radius_data_view = mpFilterRadiusTensorAdaptor->ViewData(); KRATOS_ERROR_IF_NOT(stride == mpDamping->GetStride()) - << "Damping stride and expression stride mismatch. [ damping stride = " - << mpDamping->GetStride() << ", expression stride = " << stride << " ].\n"; + << "Damping stride and tensor adaptor stride mismatch. [ damping stride = " + << mpDamping->GetStride() << ", tensor adaptor stride = " << stride << " ].\n"; auto p_result_tensor_adaptor = Kratos::make_shared>(rTensorAdaptor); auto result_data_view = p_result_tensor_adaptor->ViewData(); @@ -369,8 +369,8 @@ TensorAdaptor::Pointer ExplicitFilterUtils::GenericBackw const auto& r_filter_radius_data_view = mpFilterRadiusTensorAdaptor->ViewData(); KRATOS_ERROR_IF_NOT(stride == mpDamping->GetStride()) - << "Damping stride and expression stride mismatch. [ damping stride = " - << mpDamping->GetStride() << ", expression stride = " << stride << " ].\n"; + << "Damping stride and tensor adaptor stride mismatch. [ damping stride = " + << mpDamping->GetStride() << ", tensor adaptor stride = " << stride << " ].\n"; auto p_result_tensor_adaptor = Kratos::make_shared>(rTensorAdaptor); auto result_data_view = p_result_tensor_adaptor->ViewData(); diff --git a/applications/OptimizationApplication/custom_utilities/filtering/explicit_filter_utils.h b/applications/OptimizationApplication/custom_utilities/filtering/explicit_filter_utils.h index b3d47112af95..9a46433d550e 100644 --- a/applications/OptimizationApplication/custom_utilities/filtering/explicit_filter_utils.h +++ b/applications/OptimizationApplication/custom_utilities/filtering/explicit_filter_utils.h @@ -91,7 +91,7 @@ class KRATOS_API(OPTIMIZATION_APPLICATION) ExplicitFilterUtils * \Delta \underline{s} = \mathbf{D}\mathbf{A}\Delta \tilde{\underline{s}} * \f] * - * @param rContainerExpression mesh-independent update field in control space. + * @param rTensorAdaptor mesh-independent update field in control space. * @return TensorAdaptor::Pointer Filtered/Smoothened mesh-independent update field in physical space */ TensorAdaptor::Pointer ForwardFilterField(const TensorAdaptor& rTensorAdaptor) const; @@ -101,7 +101,7 @@ class KRATOS_API(OPTIMIZATION_APPLICATION) ExplicitFilterUtils * @details This method transforms physical space gradients to control space gradients * by using the transpose of the @ref ForwardFilterField method. * - * @param rContainerExpression Mesh-independent physical space gradient. + * @param rTensorAdaptor Mesh-independent physical space gradient. * @return TensorAdaptor::Pointer Mesh-independent control space gradient. */ TensorAdaptor::Pointer BackwardFilterField(const TensorAdaptor& rTensorAdaptor) const; @@ -111,7 +111,7 @@ class KRATOS_API(OPTIMIZATION_APPLICATION) ExplicitFilterUtils * @details This method transforms physical space gradients to control space gradients * by using the transpose of the @ref ForwardFilterField method. * - * @param rContainerExpression Mesh-dependent physical space gradient. + * @param rTensorAdaptor Mesh-dependent physical space gradient. * @return TensorAdaptor::Pointer Mesh-independent control space gradient. */ TensorAdaptor::Pointer BackwardFilterIntegratedField(const TensorAdaptor& rTensorAdaptor) const; diff --git a/applications/OptimizationApplication/custom_utilities/response/linear_strain_energy_response_utils.cpp b/applications/OptimizationApplication/custom_utilities/response/linear_strain_energy_response_utils.cpp index dd94e2b67862..b1566a39f97f 100644 --- a/applications/OptimizationApplication/custom_utilities/response/linear_strain_energy_response_utils.cpp +++ b/applications/OptimizationApplication/custom_utilities/response/linear_strain_energy_response_utils.cpp @@ -115,7 +115,7 @@ void LinearStrainEnergyResponseUtils::CalculateGradient( << "\n\t" << SHAPE.Name(); } - // now fill the container expressions + // now fill the container tensor adaptors for (auto p_tensor_adaptor : rCombinedTensorAdaptor.GetTensorAdaptors()) { std::visit([&p_tensor_adaptor, &pVariable](const auto& pContainer) { using container_type = BareType; diff --git a/applications/OptimizationApplication/custom_utilities/response/mass_response_utils.cpp b/applications/OptimizationApplication/custom_utilities/response/mass_response_utils.cpp index 6a0e2b777c14..b6a6e33df555 100644 --- a/applications/OptimizationApplication/custom_utilities/response/mass_response_utils.cpp +++ b/applications/OptimizationApplication/custom_utilities/response/mass_response_utils.cpp @@ -163,7 +163,7 @@ void MassResponseUtils::CalculateGradient( << "\n\t" << SHAPE.Name(); } - // now fill the container expressions + // now fill the container tensor adaptors for (auto p_tensor_adaptor : rCombinedTensorAdaptor.GetTensorAdaptors()) { std::visit([&p_tensor_adaptor, &pVariable](const auto& pContainer) { using container_type = BareType; From ff1c6f754c1109bcb6479bd5c5b466510b37fbaa Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Thu, 5 Feb 2026 09:08:06 +0100 Subject: [PATCH 046/116] further string changes --- .../tests/filtering/explicit_filters_tests.py | 10 +++++----- ...t_geometric_centroid_deviation_response_function.py | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/applications/OptimizationApplication/tests/filtering/explicit_filters_tests.py b/applications/OptimizationApplication/tests/filtering/explicit_filters_tests.py index 36c10508c249..c55459f45fb9 100644 --- a/applications/OptimizationApplication/tests/filtering/explicit_filters_tests.py +++ b/applications/OptimizationApplication/tests/filtering/explicit_filters_tests.py @@ -255,11 +255,11 @@ def __RunTestCase(self, filter_function_type: str, damping_function_type: str, r physical_update = vm_filter.ForwardFilterField(control_update) # Purposefully left out for debugging if required. - # self.vtu_output.AddContainerExpression("physical_space_gradient", physical_space_gradient) - # self.vtu_output.AddContainerExpression("control_space_gradient", control_space_gradient) - # self.vtu_output.AddContainerExpression("control_update", control_update) - # self.vtu_output.AddContainerExpression("physical_update", physical_update) - # self.vtu_output.AddContainerExpression("damping_coeffs", vm_filter.GetComponentDataView().GetUnBufferedData()["damping_coefficients"]) + # self.vtu_output.AddTensorAdaptor("physical_space_gradient", physical_space_gradient) + # self.vtu_output.AddTensorAdaptor("control_space_gradient", control_space_gradient) + # self.vtu_output.AddTensorAdaptor("control_update", control_update) + # self.vtu_output.AddTensorAdaptor("physical_update", physical_update) + # self.vtu_output.AddTensorAdaptor("damping_coeffs", vm_filter.GetComponentDataView().GetUnBufferedData()["damping_coefficients"]) # self.vtu_output.PrintOutput(f"output_{i+1}") # update the mesh diff --git a/applications/OptimizationApplication/tests/responses_tests/test_geometric_centroid_deviation_response_function.py b/applications/OptimizationApplication/tests/responses_tests/test_geometric_centroid_deviation_response_function.py index 06eacc529593..a9c6fe6bcbca 100644 --- a/applications/OptimizationApplication/tests/responses_tests/test_geometric_centroid_deviation_response_function.py +++ b/applications/OptimizationApplication/tests/responses_tests/test_geometric_centroid_deviation_response_function.py @@ -18,14 +18,14 @@ def setUpClass(cls): cls.response_function.Check() cls.ref_value = cls.response_function.CalculateValue() - def _CheckSensitivity(self, update_method, expression_sensitivity_retrieval_method, delta, precision): + def _CheckSensitivity(self, update_method, tensor_adaptor_sensitivity_retrieval_method, delta, precision): ref_value = self.response_function.CalculateValue() for node in self.model_part.Nodes: update_method(node, delta) value = self.response_function.CalculateValue() sensitivity = (value - ref_value)/delta update_method(node, -delta) - self.assertAlmostEqual(sensitivity, expression_sensitivity_retrieval_method(node), precision) + self.assertAlmostEqual(sensitivity, tensor_adaptor_sensitivity_retrieval_method(node), precision) def _UpdateNodalPositions(self, direction, entity, delta): if direction == 0: From 1c3ec316ea8d4f85428cb50685c776eb240224ad Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Thu, 5 Feb 2026 09:08:17 +0100 Subject: [PATCH 047/116] update response expressions --- .../binary_operator_response_function.py | 40 +++++++++-------- ...screte_value_residual_response_function.py | 13 +++--- .../responses/evaluation_response_function.py | 6 +-- .../literal_value_response_function.py | 4 +- .../responses/log_response_function.py | 14 +++--- .../utilities/response_utilities.py | 43 +++++++++---------- .../tests/test_response_utilities.py | 27 ++++++------ 7 files changed, 74 insertions(+), 73 deletions(-) diff --git a/applications/OptimizationApplication/python_scripts/responses/binary_operator_response_function.py b/applications/OptimizationApplication/python_scripts/responses/binary_operator_response_function.py index 6572a8a7e85d..e18d365a692d 100644 --- a/applications/OptimizationApplication/python_scripts/responses/binary_operator_response_function.py +++ b/applications/OptimizationApplication/python_scripts/responses/binary_operator_response_function.py @@ -2,10 +2,8 @@ from math import log import KratosMultiphysics as Kratos -import KratosMultiphysics.OptimizationApplication as KratosOA from KratosMultiphysics.OptimizationApplication.responses.response_function import ResponseFunction from KratosMultiphysics.OptimizationApplication.responses.response_function import SupportedSensitivityFieldVariableTypes -from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes from KratosMultiphysics.OptimizationApplication.utilities.model_part_utilities import ModelPartOperation from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView @@ -70,24 +68,30 @@ def CalculateValue(self) -> float: elif self.binary_operator == BinaryOperator.POWER: return v1 ** v2 - def CalculateGradient(self, physical_variable_collective_expressions: 'dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]') -> None: + def CalculateGradient(self, physical_variable_combined_tensor_adaptor: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]') -> None: v1 = EvaluateValue(self.response_function_1, self.optimization_problem) v2 = EvaluateValue(self.response_function_2, self.optimization_problem) - resp_1_physical_variable_collective_expressions = EvaluateGradient(self.response_function_1, physical_variable_collective_expressions, self.optimization_problem) - resp_2_physical_variable_collective_expressions = EvaluateGradient(self.response_function_2, physical_variable_collective_expressions, self.optimization_problem) - - for variable, collective_expression in physical_variable_collective_expressions.items(): - for result, g1, g2 in zip(collective_expression.GetContainerExpressions(), resp_1_physical_variable_collective_expressions[variable].GetContainerExpressions(), resp_2_physical_variable_collective_expressions[variable].GetContainerExpressions()): - if self.binary_operator == BinaryOperator.ADD: - result.SetExpression((g1 + g2).GetExpression()) - elif self.binary_operator == BinaryOperator.SUBTRACT: - result.SetExpression((g1 - g2).GetExpression()) - elif self.binary_operator == BinaryOperator.MULTIPLY: - result.SetExpression((g1 * v2 + g2 * v1).GetExpression()) - elif self.binary_operator == BinaryOperator.DIVIDE: - result.SetExpression((g1 / v2 - g2 * (v1 / v2 ** 2)).GetExpression()) - elif self.binary_operator == BinaryOperator.POWER: - result.SetExpression(((g1 * (v2 / v1) + g2 * log(v1)) * (v1 ** v2)).GetExpression()) + + resp_1_gradients = {variable: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(cta) for variable, cta in physical_variable_combined_tensor_adaptor.items()} + EvaluateGradient(self.response_function_1, resp_1_gradients, self.optimization_problem) + + resp_2_gradients = {variable: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(cta) for variable, cta in physical_variable_combined_tensor_adaptor.items()} + EvaluateGradient(self.response_function_2, resp_2_gradients, self.optimization_problem) + + for variable, result_cta in physical_variable_combined_tensor_adaptor.items(): + g1_cta = resp_1_gradients[variable] + g2_cta = resp_2_gradients[variable] + if self.binary_operator == BinaryOperator.ADD: + result_cta.data = g1_cta.data + g2_cta.data + elif self.binary_operator == BinaryOperator.SUBTRACT: + result_cta.data = g1_cta.data - g2_cta.data + elif self.binary_operator == BinaryOperator.MULTIPLY: + result_cta.data = g1_cta.data * v2 + g2_cta.data * v1 + elif self.binary_operator == BinaryOperator.DIVIDE: + result_cta.data = g1_cta.data / v2 - g2_cta.data * (v1 / v2 ** 2) + elif self.binary_operator == BinaryOperator.POWER: + result_cta.data = (g1_cta.data * (v2 / v1) + g2_cta.data * log(v1)) * (v1 ** v2) + Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(result_cta, perform_store_data_recursively=False, copy=False).StoreData() def GetChildResponses(self) -> 'list[ResponseFunction]': return [self.response_function_1, self.response_function_2] diff --git a/applications/OptimizationApplication/python_scripts/responses/discrete_value_residual_response_function.py b/applications/OptimizationApplication/python_scripts/responses/discrete_value_residual_response_function.py index eeff3f114aad..9edf2b73b51b 100644 --- a/applications/OptimizationApplication/python_scripts/responses/discrete_value_residual_response_function.py +++ b/applications/OptimizationApplication/python_scripts/responses/discrete_value_residual_response_function.py @@ -94,9 +94,9 @@ def CalculateValue(self) -> float: for value in self.list_of_discrete_values: if self.residual_type == "exact": - resultant.data *= (ta.data - value) ** 2 + resultant.data[:] *= (ta.data[:] - value) ** 2 elif self.residual_type == "logarithm": - resultant.data += numpy.log((ta.data[:] - value) ** 2) + resultant.data[:] += numpy.log((ta.data[:] - value) ** 2) return numpy.sum(resultant.data) @@ -107,13 +107,12 @@ def CalculateGradient(self, physical_variable_combined_tensor_adaptor: 'dict[Sup # calculate the gradients for physical_variable, cta in physical_variable_combined_tensor_adaptor.items(): if physical_variable == self.variable: - tas = cta.GetTensorAdaptors() - # initialize the current expression - for ta in tas: + # initialize the current tensor adaptor + for ta in cta.GetTensorAdaptors(): ta.data[:] = 0.0 - for ta in tas: + for ta in cta.GetTensorAdaptors(): for i, value_i in enumerate(self.list_of_discrete_values): if self.residual_type == "exact": partial_gradient_ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(ta) @@ -126,5 +125,7 @@ def CalculateGradient(self, physical_variable_combined_tensor_adaptor: 'dict[Sup ta.data[:] += partial_gradient_ta.data elif self.residual_type == "logarithm": ta.data[:] += (((values.data - value_i) ** (-2)) * (values.data - value_i) * 2.0) + + Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(cta, perform_collect_data_recursively=False, copy=False).CollectData() else: raise RuntimeError(f"Unsupported sensitivity w.r.t. {physical_variable.Name()} requested. Followings are supported sensitivity variables:\n\t{self.variable.Name()}") diff --git a/applications/OptimizationApplication/python_scripts/responses/evaluation_response_function.py b/applications/OptimizationApplication/python_scripts/responses/evaluation_response_function.py index 6ec32b3af545..14921b4a10fc 100644 --- a/applications/OptimizationApplication/python_scripts/responses/evaluation_response_function.py +++ b/applications/OptimizationApplication/python_scripts/responses/evaluation_response_function.py @@ -1,8 +1,6 @@ import KratosMultiphysics as Kratos -import KratosMultiphysics.OptimizationApplication as KratosOA from KratosMultiphysics.OptimizationApplication.responses.response_function import ResponseFunction from KratosMultiphysics.OptimizationApplication.responses.response_function import SupportedSensitivityFieldVariableTypes -from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem from KratosMultiphysics.OptimizationApplication.utilities.buffered_dict import BufferedDict @@ -43,7 +41,7 @@ def CalculateValue(self) -> float: # now calculate return self.response_function.CalculateValue() - def CalculateGradient(self, physical_variable_collective_expressions: 'dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]') -> None: + def CalculateGradient(self, physical_variable_combined_tensor_adaptor: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]') -> None: # this response is used at the top most level of the evaluated chained responses. # so this creates a new data container under the optimization problem to avoid # having to compute the same response gradient twice. @@ -53,7 +51,7 @@ def CalculateGradient(self, physical_variable_collective_expressions: 'dict[Supp # reset data of the evaluation self.__ResetEvaluationData(self, unbuffered_data, "gradients") - return self.response_function.CalculateGradient(physical_variable_collective_expressions) + return self.response_function.CalculateGradient(physical_variable_combined_tensor_adaptor) def GetChildResponses(self) -> 'list[ResponseFunction]': return [self.response_function] diff --git a/applications/OptimizationApplication/python_scripts/responses/literal_value_response_function.py b/applications/OptimizationApplication/python_scripts/responses/literal_value_response_function.py index f9b55a812697..d56f8c77eba0 100644 --- a/applications/OptimizationApplication/python_scripts/responses/literal_value_response_function.py +++ b/applications/OptimizationApplication/python_scripts/responses/literal_value_response_function.py @@ -1,7 +1,5 @@ import KratosMultiphysics as Kratos -import KratosMultiphysics.OptimizationApplication as KratosOA from KratosMultiphysics.OptimizationApplication.responses.response_function import ResponseFunction -from KratosMultiphysics.OptimizationApplication.responses.response_function import SupportedSensitivityFieldVariableTypes from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes class LiteralValueResponseFunction(ResponseFunction): @@ -28,7 +26,7 @@ def GetInfluencingModelPart(self) -> Kratos.ModelPart: def CalculateValue(self) -> float: return self.value - def CalculateGradient(self, _: 'dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]') -> None: + def CalculateGradient(self, _: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]') -> None: raise RuntimeError(f"The literal value response function does not depend on any variable, hence no gradients.") def __str__(self) -> str: diff --git a/applications/OptimizationApplication/python_scripts/responses/log_response_function.py b/applications/OptimizationApplication/python_scripts/responses/log_response_function.py index 9d6b81708ef5..12f1004022e3 100644 --- a/applications/OptimizationApplication/python_scripts/responses/log_response_function.py +++ b/applications/OptimizationApplication/python_scripts/responses/log_response_function.py @@ -1,9 +1,7 @@ from math import log import KratosMultiphysics as Kratos -import KratosMultiphysics.OptimizationApplication as KratosOA from KratosMultiphysics.OptimizationApplication.responses.response_function import ResponseFunction from KratosMultiphysics.OptimizationApplication.responses.response_function import SupportedSensitivityFieldVariableTypes -from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem from KratosMultiphysics.OptimizationApplication.utilities.response_utilities import EvaluateValue from KratosMultiphysics.OptimizationApplication.utilities.response_utilities import EvaluateGradient @@ -32,13 +30,15 @@ def GetInfluencingModelPart(self) -> Kratos.ModelPart: def CalculateValue(self) -> float: return log(EvaluateValue(self.response_function, self.optimization_problem)) - def CalculateGradient(self, physical_variable_collective_expressions: 'dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]') -> None: + def CalculateGradient(self, physical_variable_combined_tensor_adaptor: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]') -> None: v = EvaluateValue(self.response_function, self.optimization_problem) - resp_physical_variable_collective_expressions = EvaluateGradient(self.response_function, physical_variable_collective_expressions, self.optimization_problem) - for variable, collective_expression in physical_variable_collective_expressions.items(): - for result, g in zip(collective_expression.GetContainerExpressions(), resp_physical_variable_collective_expressions[variable].GetContainerExpressions()): - result.SetExpression((g / v).GetExpression()) + resp_gradients = {var: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(cta) for var, cta in physical_variable_combined_tensor_adaptor.items()} + EvaluateGradient(self.response_function, resp_gradients, self.optimization_problem) + + for variable, cta in physical_variable_combined_tensor_adaptor.items(): + cta.data = resp_gradients[variable].data / v + Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(cta, perform_collect_data_recursively=False, perform_store_data_recursively=False, copy=False).StoreData() def GetChildResponses(self) -> 'list[ResponseFunction]': return [self.response_function] diff --git a/applications/OptimizationApplication/python_scripts/utilities/response_utilities.py b/applications/OptimizationApplication/python_scripts/utilities/response_utilities.py index 50436859eca2..4a07375ea0ff 100644 --- a/applications/OptimizationApplication/python_scripts/utilities/response_utilities.py +++ b/applications/OptimizationApplication/python_scripts/utilities/response_utilities.py @@ -6,7 +6,6 @@ from KratosMultiphysics.OptimizationApplication.responses.response_function import ResponseFunction from KratosMultiphysics.OptimizationApplication.responses.evaluation_response_function import EvaluationResponseFunction from KratosMultiphysics.OptimizationApplication.responses.response_function import SupportedSensitivityFieldVariableTypes -from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView @@ -57,36 +56,36 @@ def EvaluateValue(response_function: ResponseFunction, optimization_problem: Opt else: return response_function.CalculateValue() -def EvaluateGradient(response_function: ResponseFunction, physical_variable_collective_expressions: 'dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]', optimization_problem: OptimizationProblem) -> 'dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]': - # first get the sub_collective expressions for implemented physical kratos variables - resp_physical_variable_collective_expressions: 'dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]' = {} - for variable, collective_expression in physical_variable_collective_expressions.items(): +def EvaluateGradient(response_function: ResponseFunction, physical_variable_combined_tensor_adaptors: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]', optimization_problem: OptimizationProblem): + # first get the tensor adaptors for implemented physical kratos variables + resp_physical_variable_combined_tensor_adaptors: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]' = {} + for variable, cta in physical_variable_combined_tensor_adaptors.items(): + temp_cta = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(cta, perform_store_data_recursively=False, copy=False) if variable in response_function.GetImplementedPhysicalKratosVariables(): - resp_physical_variable_collective_expressions[variable] = collective_expression.Clone() + # if the response function depends on the variable, then add it to the dictionary for future evaluation. + resp_physical_variable_combined_tensor_adaptors[variable] = temp_cta + else: + # if the response function does not depend on the variable, then assign zeros. + temp_cta.data[:] = 0.0 + temp_cta.StoreData() # store the combined ta values to its sub tensor adaptors - resp_physical_variable_collective_expressions_to_evaluate: 'dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]' = {} + resp_physical_variable_combined_tensor_adaptors_to_evaluate: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]' = {} response_data = ComponentDataView("evaluated_responses", optimization_problem).GetUnBufferedData() - for variable, collective_expression in resp_physical_variable_collective_expressions.items(): + for variable, cta in resp_physical_variable_combined_tensor_adaptors.items(): # first check whether the gradients have been already evaluated. if so, take the gradients. if response_data.HasValue(f"gradients/d{response_function.GetName()}_d{variable.Name()}"): - resp_physical_variable_collective_expressions[variable] = response_data.GetValue(f"gradients/d{response_function.GetName()}_d{variable.Name()}") + # found already evaluated gradient. Use it. + cta.SetData(response_data.GetValue(f"gradients/d{response_function.GetName()}_d{variable.Name()}").data) + cta.StoreData() # store the combined ta values to its sub tensor adaptors else: # gradients have not yet evaluated. put it to the dictionary for later evaluation - resp_physical_variable_collective_expressions_to_evaluate[variable] = collective_expression - - if len(resp_physical_variable_collective_expressions_to_evaluate) != 0: - response_function.CalculateGradient(resp_physical_variable_collective_expressions_to_evaluate) - for variable, collective_expression in resp_physical_variable_collective_expressions_to_evaluate.items(): - response_data.SetValue(f"gradients/d{response_function.GetName()}_d{variable.Name()}", collective_expression.Clone()) - resp_physical_variable_collective_expressions[variable] = collective_expression - - # now add zero values collective expressions to variables for which the response function does not have dependence - for variable, collective_expression in physical_variable_collective_expressions.items(): - if variable not in response_function.GetImplementedPhysicalKratosVariables(): - resp_physical_variable_collective_expressions[variable] = collective_expression * 0.0 + resp_physical_variable_combined_tensor_adaptors_to_evaluate[variable] = cta - return resp_physical_variable_collective_expressions + if len(resp_physical_variable_combined_tensor_adaptors_to_evaluate) != 0: + response_function.CalculateGradient(resp_physical_variable_combined_tensor_adaptors_to_evaluate) + for variable, cta in resp_physical_variable_combined_tensor_adaptors_to_evaluate.items(): + response_data.SetValue(f"gradients/d{response_function.GetName()}_d{variable.Name()}", Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(cta)) def GetResponseFunction(current_value: str, optimization_problem: OptimizationProblem) -> ResponseFunction: from KratosMultiphysics.OptimizationApplication.responses.literal_value_response_function import LiteralValueResponseFunction diff --git a/applications/OptimizationApplication/tests/test_response_utilities.py b/applications/OptimizationApplication/tests/test_response_utilities.py index b344c034c4b9..0fdf7656d9e5 100644 --- a/applications/OptimizationApplication/tests/test_response_utilities.py +++ b/applications/OptimizationApplication/tests/test_response_utilities.py @@ -1,8 +1,7 @@ import numpy as np -from math import log +from math import log, fsum import KratosMultiphysics as Kratos -import KratosMultiphysics.OptimizationApplication as KratosOA from KratosMultiphysics.OptimizationApplication.responses.response_function import ResponseFunction from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView @@ -39,9 +38,9 @@ def CalculateValue(self) -> float: self.calculate_value_calls += 1 return self.response_function.CalculateValue() - def CalculateGradient(self, physical_variable_collective_expressions: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]') -> None: + def CalculateGradient(self, physical_variable_combined_tensor_adaptor: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]') -> None: self.calculate_gradient_calls += 1 - return self.response_function.CalculateGradient(physical_variable_collective_expressions) + return self.response_function.CalculateGradient(physical_variable_combined_tensor_adaptor) class TestResponseUtilities(kratos_unittest.TestCase): @classmethod @@ -94,15 +93,14 @@ def __CheckGradients(self, sensitivity_variables: 'list[SupportedSensitivityFiel ref_value = analytical_lambda() self.assertAlmostEqual(ref_value, response_function.CalculateValue(), precision) - physical_variable_collective_expressions: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]' = {} + physical_variable_tensor_adaptors: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]' = {} fd_gradients: 'dict[SupportedSensitivityFieldVariableTypes, list[float]]' = {} for sensitivity_variable in sensitivity_variables: - ta = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, sensitivity_variable) - ta.data[:] = 0.0 - physical_variable_collective_expressions[sensitivity_variable] = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([ta], perform_collect_data_recursively=False, perform_store_data_recursively=False) + ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, sensitivity_variable), copy=False) + physical_variable_tensor_adaptors[sensitivity_variable] = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([ta]) fd_gradients[sensitivity_variable] = [] - response_function.CalculateGradient(physical_variable_collective_expressions) + response_function.CalculateGradient(physical_variable_tensor_adaptors) for node in self.model_part.Nodes: for sensitivity_variable in sensitivity_variables: @@ -113,7 +111,7 @@ def __CheckGradients(self, sensitivity_variables: 'list[SupportedSensitivityFiel for sensitivity_variable in sensitivity_variables: ta = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, sensitivity_variable) ta.data[:] = np.array(fd_gradients[sensitivity_variable], np.float64) - self.assertAlmostEqual(np.linalg.norm(ta.data - physical_variable_collective_expressions[sensitivity_variable].GetTensorAdaptors()[0].data, ord="inf"), 0.0, precision) + self.assertVectorAlmostEqual(ta.data.ravel(), physical_variable_tensor_adaptors[sensitivity_variable].data.ravel(), precision) def setUp(self) -> None: self.optimization_problem = OptimizationProblem() @@ -258,20 +256,21 @@ def test_CombinedResponseCalculateValue2(self): self.assertEqual(self.r2.calculate_gradient_calls, 1) def test_CombinedResponseCalculateValue3(self): - eval_resp = EvaluateResponseExpression("r1 + r2 + 4.0", self.optimization_problem) + eval_resp = EvaluateResponseExpression("(r1 + r2) * 1e+6 + 4.0", self.optimization_problem) eval_resp.Initialize() eval_value = eval_resp.CalculateValue() self.assertEqual(self.r1.calculate_value_calls, 1) self.assertEqual(self.r2.calculate_value_calls, 1) - self.assertEqual(eval_value, self.r1.CalculateValue() + self.r2.CalculateValue() + 4.0) + self.assertEqual(eval_value, (self.r1.CalculateValue() + self.r2.CalculateValue()) * 1e+6 + 4.0) # followings are intermediate responses, or leaf responses. Therefore they need to be # in the optimization problem self.assertTrue(self.optimization_problem.HasResponse("r1")) self.assertTrue(self.optimization_problem.HasResponse("r2")) self.assertTrue(self.optimization_problem.HasResponse("(r1+r2)")) + self.assertTrue(self.optimization_problem.HasResponse("((r1+r2)*1000000.0)")) self.assertFalse(self.optimization_problem.HasResponse("4.0")) # followings are intermediate responses, so Algorithm, ResponseRoutine do not see them. Therefore @@ -279,6 +278,7 @@ def test_CombinedResponseCalculateValue3(self): self.assertTrue(ComponentDataView("evaluated_responses", self.optimization_problem).GetBufferedData().HasValue("values/r1")) self.assertTrue(ComponentDataView("evaluated_responses", self.optimization_problem).GetBufferedData().HasValue("values/r2")) self.assertTrue(ComponentDataView("evaluated_responses", self.optimization_problem).GetBufferedData().HasValue("values/(r1+r2)")) + self.assertTrue(ComponentDataView("evaluated_responses", self.optimization_problem).GetBufferedData().HasValue("values/((r1+r2)*1000000.0)")) self.assertTrue(self.optimization_problem.HasResponse(eval_resp)) self.assertTrue(self.optimization_problem.HasResponse(eval_resp.GetName())) @@ -286,11 +286,12 @@ def test_CombinedResponseCalculateValue3(self): self.assertFalse(ComponentDataView("evaluated_responses", self.optimization_problem).GetUnBufferedData().HasValue("gradients/dr2_dPRESSURE")) self.assertFalse(ComponentDataView("evaluated_responses", self.optimization_problem).GetUnBufferedData().HasValue("gradients/d(r1+r2)_dPRESSURE")) - self.__CheckGradients([Kratos.PRESSURE], eval_resp, lambda : self.r1.CalculateValue() + self.r2.CalculateValue() + 4.0, 1e-7, 8) + self.__CheckGradients([Kratos.PRESSURE], eval_resp, lambda : (self.r1.CalculateValue() + self.r2.CalculateValue()) * 1e+6 + 4.0, 1e-9, 4) self.assertTrue(ComponentDataView("evaluated_responses", self.optimization_problem).GetUnBufferedData().HasValue("gradients/dr1_dPRESSURE")) self.assertTrue(ComponentDataView("evaluated_responses", self.optimization_problem).GetUnBufferedData().HasValue("gradients/dr2_dPRESSURE")) self.assertTrue(ComponentDataView("evaluated_responses", self.optimization_problem).GetUnBufferedData().HasValue("gradients/d(r1+r2)_dPRESSURE")) + self.assertTrue(ComponentDataView("evaluated_responses", self.optimization_problem).GetUnBufferedData().HasValue("gradients/d((r1+r2)*1000000.0)_dPRESSURE")) self.assertEqual(self.r1.calculate_gradient_calls, 1) self.assertEqual(self.r2.calculate_gradient_calls, 1) From 0a4d89596e0de4faa475b164a154c953b91b9333 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Thu, 5 Feb 2026 09:21:23 +0100 Subject: [PATCH 048/116] update implicit filter --- .../filtering/helmholtz_solver_base.py | 10 +++++--- .../filtering/implicit_filter.py | 25 ++++++++++--------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/applications/OptimizationApplication/python_scripts/filtering/helmholtz_solver_base.py b/applications/OptimizationApplication/python_scripts/filtering/helmholtz_solver_base.py index 8988bc8fa048..f363a99b6e2a 100644 --- a/applications/OptimizationApplication/python_scripts/filtering/helmholtz_solver_base.py +++ b/applications/OptimizationApplication/python_scripts/filtering/helmholtz_solver_base.py @@ -1,5 +1,6 @@ import abc import typing +import numpy # Importing the Kratos Library import KratosMultiphysics @@ -127,9 +128,12 @@ def AdvanceInTime(self, current_time: float) -> float: def Initialize(self) -> None: self._GetSolutionStrategy().Initialize() - neighbours_exp = KratosMultiphysics.Expression.NodalExpression(self.helmholtz_model_part) - KOA.ExpressionUtils.ComputeNumberOfNeighbourElements(neighbours_exp) - KratosMultiphysics.Expression.VariableExpressionIO.Write(neighbours_exp, KratosMultiphysics.NUMBER_OF_NEIGHBOUR_ELEMENTS, False) + neighbours_ta_int = KratosMultiphysics.TensorAdaptors.NodalNeighbourCountTensorAdaptor(self.helmholtz_model_part.Nodes, self.helmholtz_model_part.Elements) + neighbours_ta_int.CollectData() + + writing_ta = KratosMultiphysics.TensorAdaptors.VariableTensorAdaptor(neighbours_ta_int.GetContainer(), KratosMultiphysics.NUMBER_OF_NEIGHBOUR_ELEMENTS) + writing_ta.SetData(neighbours_ta_int.data) + writing_ta.StoreData() KratosMultiphysics.Logger.PrintInfo("::[HelmholtzSolverBase]:: Finished initialization.") def InitializeSolutionStep(self) -> None: diff --git a/applications/OptimizationApplication/python_scripts/filtering/implicit_filter.py b/applications/OptimizationApplication/python_scripts/filtering/implicit_filter.py index c7791a329baf..0a7d85607684 100644 --- a/applications/OptimizationApplication/python_scripts/filtering/implicit_filter.py +++ b/applications/OptimizationApplication/python_scripts/filtering/implicit_filter.py @@ -3,7 +3,6 @@ import KratosMultiphysics as Kratos import KratosMultiphysics.OptimizationApplication as KratosOA from KratosMultiphysics.OptimizationApplication.filtering.filter import Filter -from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import ContainerExpressionTypes from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes from KratosMultiphysics.OptimizationApplication.filtering.helmholtz_analysis import HelmholtzAnalysis @@ -94,32 +93,34 @@ def Check(self) -> None: def Finalize(self) -> None: self.filter_analysis.Finalize() - def ForwardFilterField(self, control_field: ContainerExpressionTypes) -> ContainerExpressionTypes: + def ForwardFilterField(self, control_field: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: if self.filter_analysis._GetSolver().GetOriginModelPart()[KratosOA.NUMBER_OF_SOLVERS_USING_NODES] > 1: self.__ReInitializeFilteringModelPart() return self.filter_analysis.FilterField(control_field) - def BackwardFilterField(self, physical_mesh_independent_gradient_field: ContainerExpressionTypes) -> ContainerExpressionTypes: + def BackwardFilterField(self, physical_mesh_independent_gradient_field: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: if self.filter_analysis._GetSolver().GetOriginModelPart()[KratosOA.NUMBER_OF_SOLVERS_USING_NODES] > 1: self.__ReInitializeFilteringModelPart() return self.filter_analysis.FilterField(physical_mesh_independent_gradient_field) - def BackwardFilterIntegratedField(self, physical_mesh_dependent_gradient_field: ContainerExpressionTypes) -> ContainerExpressionTypes: + def BackwardFilterIntegratedField(self, physical_mesh_dependent_gradient_field: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: if self.filter_analysis._GetSolver().GetOriginModelPart()[KratosOA.NUMBER_OF_SOLVERS_USING_NODES] > 1: self.__ReInitializeFilteringModelPart() return self.filter_analysis.FilterIntegratedField(physical_mesh_dependent_gradient_field) - def UnfilterField(self, physical_field: ContainerExpressionTypes) -> ContainerExpressionTypes: + def UnfilterField(self, physical_field: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: if self.filter_analysis._GetSolver().GetOriginModelPart()[KratosOA.NUMBER_OF_SOLVERS_USING_NODES] > 1: self.__ReInitializeFilteringModelPart() # now we get the current values - current_values = Kratos.Expression.NodalExpression(self.filter_analysis._GetComputingModelPart()) - Kratos.Expression.VariableExpressionIO.Read(current_values, self.filter_analysis._GetSolver().GetSolvingVariable(), True) + current_values_ta = Kratos.TensorAdaptors.HistoricalVariableTensorAdaptor(self.filter_analysis._GetComputingModelPart().Nodes, self.filter_analysis._GetSolver().GetSolvingVariable()) + current_values_ta.CollectData() + # now apply the physical field - self.filter_analysis.AssignExpressionDataToNodalSolution(physical_field) + self.filter_analysis.AssignTensorDataToNodalSolution(physical_field) unfiltered_field = self.filter_analysis.UnFilterField(physical_field) + # now apply back the original BCs - Kratos.Expression.VariableExpressionIO.Write(current_values, self.filter_analysis._GetSolver().GetSolvingVariable(), True) + current_values_ta.StoreData() return unfiltered_field def GetBoundaryConditions(self) -> 'list[list[Kratos.ModelPart]]': @@ -181,10 +182,10 @@ def __ApplyBoundaryConditions(self) -> None: # make all the boundaries to zero for model_part in list_of_boundary_model_parts: - zero_field = Kratos.Expression.NodalExpression(model_part) - Kratos.Expression.LiteralExpressionIO.SetData(zero_field, 0.0) for filter_variable in self.filter_variables: - Kratos.Expression.VariableExpressionIO.Write(zero_field, filter_variable, True) + zero_field = Kratos.TensorAdaptors.HistoricalVariableTensorAdaptor(model_part.Nodes, filter_variable) + zero_field.data[:] = 0.0 + zero_field.StoreData() Kratos.Logger.PrintInfo(self.__class__.__name__, f"Applied filter boundary conditions used in \"{self.GetComponentDataView().GetComponentName()}\".") From cffcce88ad58fd0315eb3e628150531cbb0507bb Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Thu, 5 Feb 2026 09:29:57 +0100 Subject: [PATCH 049/116] update material properties control --- .../test_material_properties_control.py | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/applications/OptimizationApplication/tests/control/material/test_material_properties_control.py b/applications/OptimizationApplication/tests/control/material/test_material_properties_control.py index 4a0fdd8ab6b3..7df19ff0de95 100644 --- a/applications/OptimizationApplication/tests/control/material/test_material_properties_control.py +++ b/applications/OptimizationApplication/tests/control/material/test_material_properties_control.py @@ -6,7 +6,6 @@ # Import KratosUnittest import KratosMultiphysics.KratosUnittest as kratos_unittest from KratosMultiphysics.kratos_utilities import DeleteFileIfExisting -from KratosMultiphysics.OptimizationApplication.utilities.helper_utilities import IsSameContainerExpression from KratosMultiphysics.OptimizationApplication.controls.material.material_properties_control import MaterialPropertiesControl class TestMaterialPropertiesControl(kratos_unittest.TestCase): @@ -51,11 +50,13 @@ def test_PropertiesControl(self): element.Properties[Kratos.DENSITY] = element.Id update_vector = self.properties_control.GetEmptyField() - KratosOA.PropertiesVariableExpressionIO.Read(update_vector, Kratos.DENSITY) + KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(update_vector, Kratos.DENSITY, copy=False).CollectData() # run for 3 iterations for i in range(1, 4, 1): - self.properties_control.Update(update_vector.Clone() * i) + current_ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(update_vector) + current_ta.data *= i + self.properties_control.Update(current_ta) for element in model_part.Elements: self.assertEqual(element.Properties[Kratos.DENSITY], element.Id * i) @@ -68,16 +69,16 @@ def test_PropertiesControlUpdate(self): control_model_part = self.model_part.GetSubModelPart("structure") with self.assertRaises(RuntimeError): - self.properties_control.Update(Kratos.Expression.ConditionExpression(control_model_part)) + self.properties_control.Update(Kratos.TensorAdaptors.VariableTensorAdaptor(control_model_part.Conditions, Kratos.DENSITY)) - temp = Kratos.Expression.ElementExpression(self.model_part) - KratosOA.PropertiesVariableExpressionIO.Read(temp, Kratos.DENSITY) + temp = KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(self.model_part.Elements, Kratos.DENSITY) + temp.CollectData() with self.assertRaises(RuntimeError): self.properties_control.Update(temp) - temp = Kratos.Expression.ElementExpression(control_model_part) - KratosOA.PropertiesVariableExpressionIO.Read(temp, Kratos.DENSITY) + temp = KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(control_model_part.Elements, Kratos.DENSITY) + temp.CollectData() self.properties_control.Update(temp) @@ -87,28 +88,25 @@ def test_PropertiesControlMapGradient(self): control_model_part = self.model_part.GetSubModelPart("structure") with self.assertRaises(RuntimeError): - self.properties_control.MapGradient({Kratos.DENSITY: Kratos.Expression.NodalExpression(control_model_part)}) + self.properties_control.MapGradient({Kratos.DENSITY: Kratos.TensorAdaptors.VariableTensorAdaptor(control_model_part.Nodes, Kratos.DENSITY)}) with self.assertRaises(RuntimeError): - self.properties_control.MapGradient({Kratos.DENSITY: Kratos.Expression.ElementExpression(self.model_part)}) + self.properties_control.MapGradient({Kratos.DENSITY: Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Elements, Kratos.DENSITY)}) with self.assertRaises(RuntimeError): - self.properties_control.MapGradient({Kratos.THICKNESS: Kratos.Expression.ElementExpression(control_model_part)}) + self.properties_control.MapGradient({Kratos.THICKNESS: Kratos.TensorAdaptors.VariableTensorAdaptor(control_model_part.Elements, Kratos.DENSITY)}) with self.assertRaises(RuntimeError): self.properties_control.MapGradient({ - Kratos.DENSITY: Kratos.Expression.ElementExpression(control_model_part), - Kratos.THICKNESS: Kratos.Expression.ElementExpression(control_model_part)}) + Kratos.DENSITY: Kratos.TensorAdaptors.VariableTensorAdaptor(control_model_part.Elements, Kratos.DENSITY), + Kratos.THICKNESS: Kratos.TensorAdaptors.VariableTensorAdaptor(control_model_part.Elements, Kratos.DENSITY)}) - self.assertTrue( - IsSameContainerExpression( - self.properties_control.MapGradient({Kratos.DENSITY: Kratos.Expression.ElementExpression(control_model_part)}), - Kratos.Expression.ElementExpression(control_model_part))) + self.assertTrue(self.properties_control.MapGradient({Kratos.DENSITY: Kratos.TensorAdaptors.VariableTensorAdaptor(control_model_part.Elements, Kratos.DENSITY)}).GetContainer(), control_model_part.Elements) def test_GetControlFiield(self): self.properties_control.Initialize() field = self.properties_control.GetControlField() - KratosOA.PropertiesVariableExpressionIO.Write(field, Kratos.YOUNG_MODULUS) + KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(field, Kratos.YOUNG_MODULUS, copy=False).StoreData() for element in self.model_part.Elements: properties = element.Properties self.assertEqual(properties[Kratos.DENSITY], properties[Kratos.YOUNG_MODULUS]) From 23de83f3c3a0682529644b5b5b991a3766a91305 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Thu, 5 Feb 2026 09:30:47 +0100 Subject: [PATCH 050/116] minor --- .../controls/material/material_properties_control.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/applications/OptimizationApplication/python_scripts/controls/material/material_properties_control.py b/applications/OptimizationApplication/python_scripts/controls/material/material_properties_control.py index 918c67f472be..e51babab0243 100644 --- a/applications/OptimizationApplication/python_scripts/controls/material/material_properties_control.py +++ b/applications/OptimizationApplication/python_scripts/controls/material/material_properties_control.py @@ -77,19 +77,19 @@ def GetControlField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: field.CollectData() return Kratos.TensorAdaptors.DoubleTensorAdaptor(field, copy=False) - def MapGradient(self, physical_gradient_variable_container_expression_map: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleTensorAdaptor]') -> Kratos.TensorAdaptors.DoubleTensorAdaptor: - keys = physical_gradient_variable_container_expression_map.keys() + def MapGradient(self, physical_gradient_variable_tensor_adaptor_map: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleTensorAdaptor]') -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + keys = physical_gradient_variable_tensor_adaptor_map.keys() if len(keys) != 1: raise RuntimeError(f"Provided more than required gradient fields for control \"{self.GetName()}\". Following are the variables:\n\t" + "\n\t".join([k.Name() for k in keys])) if self.controlled_physical_variable not in keys: raise RuntimeError(f"The required gradient for control \"{self.GetName()}\" w.r.t. {self.controlled_physical_variable.Name()} not found. Followings are the variables:\n\t" + "\n\t".join([k.Name() for k in keys])) - physical_gradient = physical_gradient_variable_container_expression_map[self.controlled_physical_variable] + physical_gradient = physical_gradient_variable_tensor_adaptor_map[self.controlled_physical_variable] if physical_gradient.GetContainer() != self.GetEmptyField().GetContainer(): raise RuntimeError(f"Gradients for the required element container not found for control \"{self.GetName()}\". [ required model part name: {self.model_part.FullName()} ]") # TODO: Implement filtering mechanisms here - return Kratos.TensorAdaptors.DoubleTensorAdaptor(physical_gradient_variable_container_expression_map[self.controlled_physical_variable]) + return Kratos.TensorAdaptors.DoubleTensorAdaptor(physical_gradient_variable_tensor_adaptor_map[self.controlled_physical_variable]) def Update(self, control_field: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> bool: if control_field.GetContainer() != self.GetEmptyField().GetContainer(): From 94e96de374168e1f8c2694fb25d76d83c288ef4e Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Thu, 5 Feb 2026 13:14:29 +0100 Subject: [PATCH 051/116] update simp control --- .../controls/material/simp_control.py | 69 +++++++++---------- .../control/material/test_simp_control.py | 67 +++++++++--------- 2 files changed, 68 insertions(+), 68 deletions(-) diff --git a/applications/OptimizationApplication/python_scripts/controls/material/simp_control.py b/applications/OptimizationApplication/python_scripts/controls/material/simp_control.py index 632f88ed04a5..972a396087b2 100644 --- a/applications/OptimizationApplication/python_scripts/controls/material/simp_control.py +++ b/applications/OptimizationApplication/python_scripts/controls/material/simp_control.py @@ -1,12 +1,11 @@ import typing +import numpy import KratosMultiphysics as Kratos import KratosMultiphysics.OptimizationApplication as KratosOA from KratosMultiphysics.OptimizationApplication.controls.control import Control from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem -from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import ContainerExpressionTypes from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes from KratosMultiphysics.OptimizationApplication.utilities.model_part_utilities import ModelPartOperation -from KratosMultiphysics.OptimizationApplication.utilities.helper_utilities import IsSameContainerExpression from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView from KratosMultiphysics.OptimizationApplication.filtering.filter import Factory as FilterFactory from KratosMultiphysics.OptimizationApplication.utilities.opt_projection import CreateProjection @@ -130,12 +129,12 @@ def Initialize(self) -> None: if is_density_defined: if is_youngs_modulus_defined: Kratos.Logger.PrintWarning(self.__class__.__name__, f"Elements of {self.model_part.FullName()} defines both DENSITY and YOUNG_MODULUS. Using DENSITY for initial field calculation and ignoring YOUNG_MODULUS.") - density = Kratos.Expression.ElementExpression(self.model_part) - KratosOA.PropertiesVariableExpressionIO.Read(density, Kratos.DENSITY) + density = KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(self.model_part.Elements, Kratos.DENSITY) + density.CollectData() self.simp_physical_phi = self.density_projection.ProjectBackward(density) elif is_youngs_modulus_defined: - young_modulus = Kratos.Expression.ElementExpression(self.model_part) - KratosOA.PropertiesVariableExpressionIO.Read(young_modulus, Kratos.YOUNG_MODULUS) + young_modulus = KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(self.model_part.Elements, Kratos.YOUNG_MODULUS) + young_modulus.CollectData() self.simp_physical_phi = self.young_modulus_projection.ProjectBackward(young_modulus) else: raise RuntimeError(f"Elements of {self.model_part.FullName()} does not define either DENSITY or YOUNG_MODULUS.") @@ -154,43 +153,43 @@ def Finalize(self) -> None: def GetPhysicalKratosVariables(self) -> 'list[SupportedSensitivityFieldVariableTypes]': return self.controlled_physical_variables - def GetEmptyField(self) -> ContainerExpressionTypes: - field = Kratos.Expression.ElementExpression(self.model_part) - Kratos.Expression.LiteralExpressionIO.SetData(field, 0.0) - return field + def GetEmptyField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + field = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Elements, Kratos.DENSITY) + field.data[:] = 0.0 + return Kratos.TensorAdaptors.DoubleTensorAdaptor(field, copy=False) - def GetControlField(self) -> ContainerExpressionTypes: - return self.control_phi.Clone() + def GetControlField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + return Kratos.TensorAdaptors.DoubleTensorAdaptor(self.control_phi) # returning a copy - def MapGradient(self, physical_gradient_variable_container_expression_map: 'dict[SupportedSensitivityFieldVariableTypes, ContainerExpressionTypes]') -> ContainerExpressionTypes: - keys = physical_gradient_variable_container_expression_map.keys() + def MapGradient(self, physical_gradient_variable_tensor_adaptor_map: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleTensorAdaptor]') -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + keys = physical_gradient_variable_tensor_adaptor_map.keys() if len(keys) != 2: raise RuntimeError(f"Not provided required gradient fields for control \"{self.GetName()}\". Following are the variables:\n\t" + "\n\t".join([k.Name() for k in keys])) if Kratos.DENSITY not in keys or Kratos.YOUNG_MODULUS not in keys: raise RuntimeError(f"The required gradient for control \"{self.GetName()}\" w.r.t. DENSITY or YOUNG_MODULUS not found. Followings are the variables:\n\t" + "\n\t".join([k.Name() for k in keys])) # first calculate the density partial sensitivity of the response function - d_j_d_density = physical_gradient_variable_container_expression_map[Kratos.DENSITY] + d_j_d_density = physical_gradient_variable_tensor_adaptor_map[Kratos.DENSITY] # second calculate the young modulus partial sensitivity of the response function - d_j_d_youngs = physical_gradient_variable_container_expression_map[Kratos.YOUNG_MODULUS] + d_j_d_youngs = physical_gradient_variable_tensor_adaptor_map[Kratos.YOUNG_MODULUS] # now compute response function total sensitivity w.r.t. phi - d_j_d_phi = d_j_d_density * self.d_density_d_phi + d_j_d_youngs * self.d_young_modulus_d_phi + d_j_d_phi = Kratos.TensorAdaptors.DoubleTensorAdaptor(d_j_d_density) + d_j_d_phi.data = d_j_d_density.data * self.d_density_d_phi.data + d_j_d_youngs.data * self.d_young_modulus_d_phi.data return self.filter.BackwardFilterIntegratedField(d_j_d_phi) - def Update(self, control_field: ContainerExpressionTypes) -> bool: - if not IsSameContainerExpression(control_field, self.GetEmptyField()): - raise RuntimeError(f"Updates for the required element container not found for control \"{self.GetName()}\". [ required model part name: {self.model_part.FullName()}, given model part name: {control_field.GetModelPart().FullName()} ]") + def Update(self, control_field: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> bool: + if control_field.GetContainer() != self.model_part.Elements: + raise RuntimeError(f"Updates for the required element container not found for control \"{self.GetName()}\". [ required model part name: {self.model_part.FullName()} ]") - update = control_field - self.control_phi - if Kratos.Expression.Utils.NormL2(update) > 1e-15: - self.control_phi = control_field + update = Kratos.TensorAdaptors.DoubleTensorAdaptor(control_field) + update.data = control_field.data - self.control_phi.data + if numpy.linalg.norm(update.data) > 1e-15: + self.control_phi.data[:] = control_field.data[:] self._UpdateAndOutputFields(update) self.filter.Update() - return True - self.density_projection.Update() self.young_modulus_projection.Update() return True @@ -199,22 +198,22 @@ def Update(self, control_field: ContainerExpressionTypes) -> bool: self.young_modulus_projection.Update() return False - def _UpdateAndOutputFields(self, update: ContainerExpressionTypes) -> None: + def _UpdateAndOutputFields(self, update: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> None: # filter the control field physical_phi_update = self.filter.ForwardFilterField(update) - self.simp_physical_phi = Kratos.Expression.Utils.Collapse(self.simp_physical_phi + physical_phi_update) + self.simp_physical_phi.data += physical_phi_update.data density = self.density_projection.ProjectForward(self.simp_physical_phi) - KratosOA.PropertiesVariableExpressionIO.Write(density, Kratos.DENSITY) + KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(density, Kratos.DENSITY, copy=False).StoreData() if self.consider_recursive_property_update: KratosOA.OptimizationUtils.UpdatePropertiesVariableWithRootValueRecursively(density.GetContainer(), Kratos.DENSITY) - self.un_buffered_data.SetValue("DENSITY", density.Clone(), overwrite=True) + self.un_buffered_data.SetValue("DENSITY", density, overwrite=True) youngs_modulus = self.young_modulus_projection.ProjectForward(self.simp_physical_phi) - KratosOA.PropertiesVariableExpressionIO.Write(youngs_modulus, Kratos.YOUNG_MODULUS) + KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(youngs_modulus, Kratos.YOUNG_MODULUS, copy=False).StoreData() if self.consider_recursive_property_update: KratosOA.OptimizationUtils.UpdatePropertiesVariableWithRootValueRecursively(youngs_modulus.GetContainer(), Kratos.YOUNG_MODULUS) - self.un_buffered_data.SetValue("YOUNG_MODULUS", youngs_modulus.Clone(), overwrite=True) + self.un_buffered_data.SetValue("YOUNG_MODULUS", youngs_modulus, overwrite=True) # now calculate the total sensitivities of density w.r.t. phi self.d_density_d_phi = self.density_projection.ForwardProjectionGradient(self.simp_physical_phi) @@ -224,8 +223,8 @@ def _UpdateAndOutputFields(self, update: ContainerExpressionTypes) -> None: # now output the fields un_buffered_data = ComponentDataView(self, self.optimization_problem).GetUnBufferedData() - un_buffered_data.SetValue(f"{self.GetName()}", self.simp_physical_phi.Clone(),overwrite=True) + un_buffered_data.SetValue(f"{self.GetName()}", Kratos.TensorAdaptors.DoubleTensorAdaptor(self.simp_physical_phi),overwrite=True) if self.output_all_fields: - un_buffered_data.SetValue(f"{self.GetName()}_update", physical_phi_update.Clone(), overwrite=True) - un_buffered_data.SetValue(f"dDENSITY_d{self.GetName()}", self.d_density_d_phi.Clone(), overwrite=True) - un_buffered_data.SetValue(f"dYOUNG_MODULUS_d{self.GetName()}", self.d_young_modulus_d_phi.Clone(), overwrite=True) + un_buffered_data.SetValue(f"{self.GetName()}_update", physical_phi_update, overwrite=True) + un_buffered_data.SetValue(f"dDENSITY_d{self.GetName()}", Kratos.TensorAdaptors.DoubleTensorAdaptor(self.d_density_d_phi), overwrite=True) + un_buffered_data.SetValue(f"dYOUNG_MODULUS_d{self.GetName()}", Kratos.TensorAdaptors.DoubleTensorAdaptor(self.d_young_modulus_d_phi), overwrite=True) diff --git a/applications/OptimizationApplication/tests/control/material/test_simp_control.py b/applications/OptimizationApplication/tests/control/material/test_simp_control.py index 3293bf7bce57..099cdb7e6769 100644 --- a/applications/OptimizationApplication/tests/control/material/test_simp_control.py +++ b/applications/OptimizationApplication/tests/control/material/test_simp_control.py @@ -1,4 +1,5 @@ +import numpy import KratosMultiphysics as Kratos import KratosMultiphysics.OptimizationApplication as KratosOA @@ -86,11 +87,11 @@ def setUpClass(cls): Kratos.ReadMaterialsUtility(cls.model).ReadMaterials(material_params) cls.simp_control.Initialize() - cls.initial_density = Kratos.Expression.ElementExpression(cls.model_part) - KratosOA.PropertiesVariableExpressionIO.Read(cls.initial_density, Kratos.DENSITY) + cls.initial_density = KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(cls.model_part.Elements, Kratos.DENSITY) + cls.initial_density.CollectData() def setUp(self) -> None: - KratosOA.PropertiesVariableExpressionIO.Write(self.initial_density, Kratos.DENSITY) + self.initial_density.StoreData() @classmethod def tearDownClass(cls): @@ -99,7 +100,7 @@ def tearDownClass(cls): def test_GetControlField(self): control_field = self.simp_control.GetControlField() - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(control_field), 0.0, 4) + self.assertAlmostEqual(numpy.linalg.norm(control_field.data), 0.0, 10) def test_MapGradient(self): physical_rho_gradient = self.simp_control.GetEmptyField() @@ -107,39 +108,39 @@ def test_MapGradient(self): for element in physical_rho_gradient.GetContainer(): element.SetValue(KratosOA.DENSITY_SENSITIVITY, element.GetGeometry().DomainSize()) element.SetValue(KratosOA.YOUNG_MODULUS_SENSITIVITY, element.GetGeometry().DomainSize()/1e+10) - Kratos.Expression.VariableExpressionIO.Read(physical_rho_gradient, KratosOA.DENSITY_SENSITIVITY) - Kratos.Expression.VariableExpressionIO.Read(physical_E_gradient, KratosOA.YOUNG_MODULUS_SENSITIVITY) + Kratos.TensorAdaptors.VariableTensorAdaptor(physical_rho_gradient, KratosOA.DENSITY_SENSITIVITY, copy=False).CollectData() + Kratos.TensorAdaptors.VariableTensorAdaptor(physical_E_gradient, KratosOA.YOUNG_MODULUS_SENSITIVITY, copy=False).CollectData() mapped_gradient = self.simp_control.MapGradient({Kratos.DENSITY: physical_rho_gradient, Kratos.YOUNG_MODULUS: physical_E_gradient}) - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(mapped_gradient), 15731.035, 4) + self.assertAlmostEqual(numpy.linalg.norm(mapped_gradient.data), 15731.035, 4) def test_Update(self): - rho_field = Kratos.Expression.ElementExpression(self.model_part) - KratosOA.PropertiesVariableExpressionIO.Read(rho_field, Kratos.DENSITY) - E_field = Kratos.Expression.ElementExpression(self.model_part) - KratosOA.PropertiesVariableExpressionIO.Read(E_field, Kratos.YOUNG_MODULUS) + rho_field = KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(self.model_part.Elements, Kratos.DENSITY) + rho_field.CollectData() + E_field = KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(self.model_part.Elements, Kratos.YOUNG_MODULUS) + E_field.CollectData() # update with empty field update_field = self.simp_control.GetEmptyField() self.simp_control.Update(update_field) - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(self.simp_control.GetControlField()), 0.0) - updated_rho_field = Kratos.Expression.ElementExpression(self.model_part) - KratosOA.PropertiesVariableExpressionIO.Read(updated_rho_field, Kratos.DENSITY) - updated_E_field = Kratos.Expression.ElementExpression(self.model_part) - KratosOA.PropertiesVariableExpressionIO.Read(updated_E_field, Kratos.YOUNG_MODULUS) - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(updated_rho_field - rho_field), 0.0) - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(updated_E_field - E_field), 0.0) + self.assertAlmostEqual(numpy.linalg.norm(self.simp_control.GetControlField().data), 0.0) + updated_rho_field = KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(self.model_part.Elements, Kratos.DENSITY) + updated_rho_field.CollectData() + updated_E_field = KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(self.model_part.Elements, Kratos.YOUNG_MODULUS) + updated_E_field.CollectData() + self.assertVectorAlmostEqual(updated_rho_field.data, rho_field.data, 9) + self.assertVectorAlmostEqual(updated_E_field.data, E_field.data, 9) - Kratos.Expression.LiteralExpressionIO.SetData(update_field, 0.75) + update_field.data[:] = 0.75 self.simp_control.Update(update_field) control_field = self.simp_control.GetControlField() - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(control_field), 0.75, 4) + self.assertAlmostEqual(numpy.linalg.norm(control_field.data, ord=numpy.inf), 0.75, 4) - KratosOA.PropertiesVariableExpressionIO.Read(updated_rho_field, Kratos.DENSITY) - KratosOA.PropertiesVariableExpressionIO.Read(updated_E_field, Kratos.YOUNG_MODULUS) - self.assertTrue(Kratos.Expression.Utils.NormInf(updated_rho_field - rho_field) > 0.0) - self.assertTrue(Kratos.Expression.Utils.NormInf(updated_E_field - E_field) > 0.0) - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(updated_rho_field), 14955.413791112203) - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(updated_E_field), 357673554186.7966) + updated_rho_field.CollectData() + updated_E_field.CollectData() + self.assertTrue(numpy.linalg.norm(updated_rho_field.data - rho_field.data, ord=numpy.inf) > 0.0) + self.assertTrue(numpy.linalg.norm(updated_E_field.data - E_field.data, ord=numpy.inf) > 0.0) + self.assertAlmostEqual(numpy.linalg.norm(updated_rho_field.data), 14955.413791112203) + self.assertAlmostEqual(numpy.linalg.norm(updated_E_field.data), 357673554186.7966) def test_AdaptiveBeta(self): parameters = Kratos.Parameters("""{ @@ -194,8 +195,8 @@ def test_AdaptiveBeta(self): control_field = simp_control.GetControlField() simp_control.Update(control_field) for i in range(20): - control_field *= 1.2 - simp_control.Update(control_field) + control_field.data += 1.2 + self.assertTrue(simp_control.Update(control_field)) self.optimization_problem.AdvanceStep() self.assertAlmostEqual(simp_control.density_projection.beta, 0.01 * (1.05 ** 7)) @@ -253,12 +254,12 @@ def test_NonRemovalOfMaterials(self): control_field = simp_control.GetControlField() simp_control.Update(control_field) for i in range(20): - control_field *= 1.2 - simp_control.Update(control_field) + control_field.data *= 1.2 + self.assertFalse(simp_control.Update(control_field)) - density = Kratos.Expression.ElementExpression(self.model_part) - KratosOA.PropertiesVariableExpressionIO.Read(density, Kratos.DENSITY) - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(density - 3925), 0.0) + density = KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(self.model_part.Elements, Kratos.DENSITY) + density.CollectData() + self.assertAlmostEqual(numpy.linalg.norm(density.data - 3925), 0.0) if __name__ == "__main__": kratos_unittest.main() \ No newline at end of file From ee16838d6cab517314196c36dbea10f36f3d0574 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 6 Feb 2026 05:42:33 +0100 Subject: [PATCH 052/116] update shape control --- .../shape/vertex_morphing_shape_control.py | 94 +++++++++++-------- .../control/shape/test_vm_shape_control.py | 75 +++++++-------- 2 files changed, 86 insertions(+), 83 deletions(-) diff --git a/applications/OptimizationApplication/python_scripts/controls/shape/vertex_morphing_shape_control.py b/applications/OptimizationApplication/python_scripts/controls/shape/vertex_morphing_shape_control.py index edcbf316ffc1..dc70541789ca 100644 --- a/applications/OptimizationApplication/python_scripts/controls/shape/vertex_morphing_shape_control.py +++ b/applications/OptimizationApplication/python_scripts/controls/shape/vertex_morphing_shape_control.py @@ -1,11 +1,10 @@ +import numpy from typing import Optional import KratosMultiphysics as Kratos import KratosMultiphysics.OptimizationApplication as KratosOA from KratosMultiphysics.OptimizationApplication.controls.control import Control -from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import ContainerExpressionTypes from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes -from KratosMultiphysics.OptimizationApplication.utilities.helper_utilities import IsSameContainerExpression from KratosMultiphysics.OptimizationApplication.utilities.model_part_utilities import ModelPartOperation from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem @@ -115,44 +114,45 @@ def Finalize(self) -> None: def GetPhysicalKratosVariables(self) -> 'list[SupportedSensitivityFieldVariableTypes]': return [KratosOA.SHAPE] - def GetEmptyField(self) -> ContainerExpressionTypes: - field = Kratos.Expression.NodalExpression(self.__GetPhysicalModelPart()) - Kratos.Expression.LiteralExpressionIO.SetData(field, [0,0,0]) + def GetEmptyField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + field = Kratos.TensorAdaptors.VariableTensorAdaptor(self.__GetPhysicalModelPart().Nodes, KratosOA.SHAPE) + field.data[:] = 0.0 return field - def GetControlField(self) -> ContainerExpressionTypes: - return self.control_field + def GetControlField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + return Kratos.TensorAdaptors.DoubleTensorAdaptor(self.control_field) - def GetPhysicalField(self) -> ContainerExpressionTypes: - physical_shape_field = Kratos.Expression.NodalExpression(self.__GetPhysicalModelPart()) - Kratos.Expression.NodalPositionExpressionIO.Read(physical_shape_field, Kratos.Configuration.Initial) + def GetPhysicalField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + physical_shape_field = Kratos.TensorAdaptors.NodePositionTensorAdaptor(self.__GetPhysicalModelPart().Nodes, Kratos.Configuration.Initial) + physical_shape_field.CollectData() return physical_shape_field @time_decorator(methodName="GetName") - def MapGradient(self, physical_gradient_variable_container_expression_map: 'dict[SupportedSensitivityFieldVariableTypes, ContainerExpressionTypes]') -> ContainerExpressionTypes: - keys = physical_gradient_variable_container_expression_map.keys() + def MapGradient(self, physical_gradient_variable_tensor_adaptor_map: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleTensorAdaptor]') -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + keys = physical_gradient_variable_tensor_adaptor_map.keys() if len(keys) != 1: raise RuntimeError(f"Provided more than required gradient fields for control \"{self.GetName()}\". Following are the variables:\n\t" + "\n\t".join([k.Name() for k in keys])) if KratosOA.SHAPE not in keys: raise RuntimeError(f"The required gradient for control \"{self.GetName()}\" w.r.t. {KratosOA.SHAPE.Name()} not found. Followings are the variables:\n\t" + "\n\t".join([k.Name() for k in keys])) - physical_gradient = physical_gradient_variable_container_expression_map[KratosOA.SHAPE] - if not IsSameContainerExpression(physical_gradient, self.GetEmptyField()): + physical_gradient = physical_gradient_variable_tensor_adaptor_map[KratosOA.SHAPE] + if physical_gradient.GetContainer() != self.__GetPhysicalModelPart().Nodes: raise RuntimeError(f"Gradients for the required element container not found for control \"{self.GetName()}\". [ required model part name: {self.model_part.FullName()}, given model part name: {physical_gradient.GetModelPart().FullName()} ]") - filtered_gradient = self.filter.BackwardFilterIntegratedField(KratosOA.ExpressionUtils.ExtractData(physical_gradient, self.model_part)) + filtered_gradient = self.filter.BackwardFilterIntegratedField(self.__ExtractTensorData(KratosOA.SHAPE, physical_gradient, self.model_part.Nodes)) - return KratosOA.ExpressionUtils.ExtractData(filtered_gradient, self.__GetPhysicalModelPart()) + return self.__ExtractTensorData(KratosOA.SHAPE, filtered_gradient, self.__GetPhysicalModelPart().Nodes) @time_decorator(methodName="GetName") - def Update(self, new_control_field: ContainerExpressionTypes) -> bool: - if not IsSameContainerExpression(new_control_field, self.GetEmptyField()): + def Update(self, new_control_field: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> bool: + if new_control_field.GetContainer() != self.__GetPhysicalModelPart().Nodes: raise RuntimeError(f"Updates for the required element container not found for control \"{self.GetName()}\". [ required model part name: {self.model_part.FullName()}, given model part name: {new_control_field.GetModelPart().FullName()} ]") - diff_norm = Kratos.Expression.Utils.NormL2(self.control_field - new_control_field) - if not math.isclose(diff_norm, 0.0, abs_tol=1e-16): + + control_update = Kratos.TensorAdaptors.DoubleTensorAdaptor(new_control_field) + control_update.data = new_control_field.data - self.control_field.data + if not math.isclose(numpy.linalg.norm(control_update.data), 0.0, abs_tol=1e-16): # update the control SHAPE field - control_update = new_control_field - self.control_field - self.control_field = new_control_field + self.control_field.data[:] = new_control_field.data[:] # now update the physical field self._UpdateAndOutputFields(control_update) @@ -160,27 +160,25 @@ def Update(self, new_control_field: ContainerExpressionTypes) -> bool: return True return False - def _UpdateAndOutputFields(self, control_update: ContainerExpressionTypes) -> None: + def _UpdateAndOutputFields(self, control_update: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> None: # compute the shape update if self.mesh_motion_solver_type == "filter_based": shape_update = self.filter.ForwardFilterField(control_update) else: - shape_update = self.filter.ForwardFilterField(KratosOA.ExpressionUtils.ExtractData(control_update, self.model_part)) + shape_update = self.filter.ForwardFilterField(self.__ExtractTensorData(KratosOA.SHAPE, control_update, self.model_part.Nodes)) # now update the shape self._UpdateMesh(shape_update) # now output the fields un_buffered_data = ComponentDataView(self, self.optimization_problem).GetUnBufferedData() - un_buffered_data.SetValue("shape_update", shape_update.Clone(),overwrite=True) + un_buffered_data.SetValue("shape_update", shape_update,overwrite=True) if self.output_all_fields: - un_buffered_data.SetValue("shape_control", self.control_field.Clone(),overwrite=True) - un_buffered_data.SetValue("shape_control_update", control_update.Clone(),overwrite=True) + un_buffered_data.SetValue("shape_control", Kratos.TensorAdaptors.DoubleTensorAdaptor(self.control_field), overwrite=True) + un_buffered_data.SetValue("shape_control_update", control_update, overwrite=True) - def _UpdateMesh(self, shape_update: ContainerExpressionTypes) -> None: + def _UpdateMesh(self, shape_update: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> None: if self.mesh_motion_solver_type != "none": - mesh_displacement_field = Kratos.Expression.NodalExpression(self.model_part_operation.GetRootModelPart()) - if not self.__mesh_moving_analysis is None: mm_computing_model_part: Kratos.ModelPart = self.__mesh_moving_analysis._GetSolver().GetComputingModelPart() time_before_update = mm_computing_model_part.ProcessInfo.GetValue(Kratos.TIME) @@ -196,7 +194,7 @@ def _UpdateMesh(self, shape_update: ContainerExpressionTypes) -> None: Kratos.VariableUtils().SetHistoricalVariableToZero(Kratos.MESH_DISPLACEMENT, mm_computing_model_part.Nodes) # assign the design surface MESH_DISPLACEMENTS - Kratos.Expression.VariableExpressionIO.Write(shape_update, Kratos.MESH_DISPLACEMENT, True) + Kratos.TensorAdaptors.HistoricalVariableTensorAdaptor(shape_update, Kratos.MESH_DISPLACEMENT, copy=False).StoreData() # since we know that the nodes in the shape_update model part needs to be fixed to correctly # compute the MESH_DISPLACEMENT. We Only do that in here by first freeing all the MESH_DISPLACEMENT @@ -208,7 +206,7 @@ def _UpdateMesh(self, shape_update: ContainerExpressionTypes) -> None: # first free the mesh displacement component Kratos.VariableUtils().ApplyFixity(mesh_displacement_var, False, mm_computing_model_part.Nodes) # now fix the design surface component - Kratos.VariableUtils().ApplyFixity(mesh_displacement_var, True, shape_update.GetModelPart().Nodes) + Kratos.VariableUtils().ApplyFixity(mesh_displacement_var, True, shape_update.GetContainer()) # now fix boundary condition components model_parts = self.filter.GetBoundaryConditions() for model_part in model_parts[i_comp]: @@ -219,29 +217,31 @@ def _UpdateMesh(self, shape_update: ContainerExpressionTypes) -> None: self.__mesh_moving_analysis.end_time += 1 self.__mesh_moving_analysis.RunSolutionLoop() - Kratos.Expression.VariableExpressionIO.Read(mesh_displacement_field, Kratos.MESH_DISPLACEMENT, True) + mesh_displacement_field = Kratos.TensorAdaptors.HistoricalVariableTensorAdaptor(self.model_part_operation.GetRootModelPart().Nodes, Kratos.MESH_DISPLACEMENT) + mesh_displacement_field.CollectData() mm_computing_model_part.ProcessInfo.SetValue(Kratos.STEP, step_before_update) mm_computing_model_part.ProcessInfo.SetValue(Kratos.TIME, time_before_update) mm_computing_model_part.ProcessInfo.SetValue(Kratos.DELTA_TIME, delta_time_before_update) else: # filter based mesh motion is used. Hence read the value from the filter. then the shape update is the mesh displacement - mesh_displacement_field = shape_update.Clone() + mesh_displacement_field = shape_update # a mesh motion is solved (either by mesh motion solver or the filter), and MESH_DISPLACEMENT variable is filled # Hence, update the coords - physical_field = Kratos.Expression.NodalExpression(self.model_part_operation.GetRootModelPart()) - - Kratos.Expression.NodalPositionExpressionIO.Read(physical_field, Kratos.Configuration.Initial) + physical_field = Kratos.TensorAdaptors.NodePositionTensorAdaptor(mesh_displacement_field.GetContainer(), Kratos.Configuration.Initial) + physical_field.CollectData() + physical_field.data += mesh_displacement_field.data - Kratos.Expression.NodalPositionExpressionIO.Write(mesh_displacement_field + physical_field, Kratos.Configuration.Initial) - Kratos.Expression.NodalPositionExpressionIO.Write(mesh_displacement_field + physical_field, Kratos.Configuration.Current) + Kratos.TensorAdaptors.NodePositionTensorAdaptor(physical_field, Kratos.Configuration.Initial, copy=False).StoreData() + Kratos.TensorAdaptors.NodePositionTensorAdaptor(physical_field, Kratos.Configuration.Current, copy=False).StoreData() Kratos.Logger.PrintInfo(self.__class__.__name__, "Applied MESH_DISPLACEMENT to the mesh.") else: # no mesh motion is preferred, hence only updating the design field physical_field = self.GetPhysicalField() - Kratos.Expression.NodalPositionExpressionIO.Write(shape_update + physical_field, Kratos.Configuration.Initial) - Kratos.Expression.NodalPositionExpressionIO.Write(shape_update + physical_field, Kratos.Configuration.Current) + physical_field.data += shape_update.data + Kratos.TensorAdaptors.NodePositionTensorAdaptor(physical_field, Kratos.Configuration.Initial, copy=False).StoreData() + Kratos.TensorAdaptors.NodePositionTensorAdaptor(physical_field, Kratos.Configuration.Current, copy=False).StoreData() def __GetPhysicalModelPart(self) -> Kratos.ModelPart: if self.mesh_motion_solver_type == "none": @@ -256,5 +256,17 @@ def __GetPhysicalModelPart(self) -> Kratos.ModelPart: # model part return self.model_part.GetRootModelPart() + def __ExtractTensorData(self, variable, tensor_adaptor: Kratos.TensorAdaptors.DoubleTensorAdaptor, nodes_container: Kratos.NodesArray) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + if nodes_container != tensor_adaptor.GetContainer(): + Kratos.VariableUtils().SetNonHistoricalVariableToZero(variable, tensor_adaptor.GetContainer()) + Kratos.VariableUtils().SetNonHistoricalVariableToZero(variable, nodes_container) + + Kratos.TensorAdaptors.VariableTensorAdaptor(tensor_adaptor, variable, copy=False).StoreData() + ta = Kratos.TensorAdaptors.VariableTensorAdaptor(nodes_container, variable) + ta.CollectData() + return ta + else: + return tensor_adaptor + def __str__(self) -> str: return f"Control [type = {self.__class__.__name__}, name = {self.GetName()}, model part name = {self.model_part.FullName()}, control variable = SHAPE ]" \ No newline at end of file diff --git a/applications/OptimizationApplication/tests/control/shape/test_vm_shape_control.py b/applications/OptimizationApplication/tests/control/shape/test_vm_shape_control.py index 1a68fc1f7a34..5d0394a30533 100644 --- a/applications/OptimizationApplication/tests/control/shape/test_vm_shape_control.py +++ b/applications/OptimizationApplication/tests/control/shape/test_vm_shape_control.py @@ -1,5 +1,5 @@ -import abc +import abc, numpy import KratosMultiphysics as Kratos from KratosMultiphysics.testing.utilities import ReadModelPart @@ -47,12 +47,12 @@ def setUpClass(cls) -> None: cls.implicit_shape_control.Initialize() cls.explicit_shape_control.Initialize() - cls.initial_nodal_positions_exp = Kratos.Expression.NodalExpression(cls.model_part) - Kratos.Expression.NodalPositionExpressionIO.Read(cls.initial_nodal_positions_exp, Kratos.Configuration.Initial) + cls.initial_nodal_positions_ta = Kratos.TensorAdaptors.NodePositionTensorAdaptor(cls.model_part.Nodes, Kratos.Configuration.Initial) + cls.initial_nodal_positions_ta.CollectData() def setUp(self) -> None: - Kratos.Expression.NodalPositionExpressionIO.Write(self.initial_nodal_positions_exp, Kratos.Configuration.Initial) - Kratos.Expression.NodalPositionExpressionIO.Write(self.initial_nodal_positions_exp, Kratos.Configuration.Current) + Kratos.TensorAdaptors.NodePositionTensorAdaptor(self.initial_nodal_positions_ta, Kratos.Configuration.Initial, copy=False).StoreData() + Kratos.TensorAdaptors.NodePositionTensorAdaptor(self.initial_nodal_positions_ta, Kratos.Configuration.Current, copy=False).StoreData() @classmethod def tearDownClass(cls): @@ -106,45 +106,41 @@ def GetMdpaFileName(self) -> str: return "shell" def test_GetControlField(self): - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(self.implicit_shape_control.GetControlField()), 22.4268730405143, 10) - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(self.explicit_shape_control.GetControlField()), 0.0, 10) + self.assertAlmostEqual(numpy.linalg.norm(self.implicit_shape_control.GetControlField().data), 22.4268730405143, 10) + self.assertAlmostEqual(numpy.linalg.norm(self.explicit_shape_control.GetControlField().data), 0.0, 10) def test_GetPhysicalField(self): shape_field = self.implicit_shape_control.GetPhysicalField() - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(shape_field), 20.976176963410882, 10) + self.assertAlmostEqual(numpy.linalg.norm(shape_field.data), 20.976176963410882, 10) shape_field = self.explicit_shape_control.GetPhysicalField() - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(shape_field), 20.976176963410882, 10) + self.assertAlmostEqual(numpy.linalg.norm(shape_field.data), 20.976176963410882, 10) def test_MapGradient(self): physical_gradient = self.implicit_shape_control.GetEmptyField() - ta_physical_gradient = Kratos.TensorAdaptors.DoubleTensorAdaptor(physical_gradient.GetContainer(), Kratos.DoubleNDData(physical_gradient.Evaluate()), copy=False) - ta_physical_gradient.data[:] = 1.0 - self.explicit_shape_control.filter.filter_utils.GetIntegrationWeights(ta_physical_gradient) - Kratos.Expression.CArrayExpressionIO.Read(physical_gradient, ta_physical_gradient.data) + physical_gradient.data[:] = 1.0 + self.explicit_shape_control.filter.filter_utils.GetIntegrationWeights(physical_gradient) implicit_mapped_gradient = self.implicit_shape_control.MapGradient({KratosOA.SHAPE: physical_gradient}) - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(implicit_mapped_gradient), 27.84296340221239, 10) + self.assertAlmostEqual(numpy.linalg.norm(implicit_mapped_gradient.data), 27.84296340221239, 10) explicit_mapped_gradient = self.explicit_shape_control.MapGradient({KratosOA.SHAPE: physical_gradient}) - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(explicit_mapped_gradient), 28.075348639115425, 10) + self.assertAlmostEqual(numpy.linalg.norm(explicit_mapped_gradient.data), 28.075348639115425, 10) def test_UpdateImplicit(self): update_field = self.implicit_shape_control.GetEmptyField() - constant_field_value = Kratos.Array3([0.1, 0.1, 0.1]) - Kratos.Expression.LiteralExpressionIO.SetData(update_field, constant_field_value) + update_field.data[:] = 0.1 self.implicit_shape_control.Update(update_field) implicit_control_field = self.implicit_shape_control.GetControlField() implicit_shape_field = self.implicit_shape_control.GetPhysicalField() - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(implicit_control_field), 3.633180424916991, 10) - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(implicit_shape_field), 10.365298105786017, 10) + self.assertAlmostEqual(numpy.linalg.norm(implicit_control_field.data), 3.633180424916991, 10) + self.assertAlmostEqual(numpy.linalg.norm(implicit_shape_field.data), 10.365298105786017, 10) def test_UpdateExplicit(self): update_field = self.explicit_shape_control.GetEmptyField() - constant_field_value = Kratos.Array3([0.1, 0.1, 0.1]) - Kratos.Expression.LiteralExpressionIO.SetData(update_field, constant_field_value) + update_field.data[:] = 0.1 self.explicit_shape_control.Update(update_field) explicit_control_field = self.explicit_shape_control.GetControlField() explicit_shape_field = self.explicit_shape_control.GetPhysicalField() - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(explicit_control_field), 3.633180424916991, 10) - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(explicit_shape_field), 22.013379276492945, 10) + self.assertAlmostEqual(numpy.linalg.norm(explicit_control_field.data), 3.633180424916991, 10) + self.assertAlmostEqual(numpy.linalg.norm(explicit_shape_field.data), 22.013379276492945, 10) @kratos_unittest.skipIfApplicationsNotAvailable("StructuralMechanicsApplication", "MeshMovingApplication") class TestVMShapeControlSolid(TestVMShapeControlBase, kratos_unittest.TestCase): @@ -212,48 +208,43 @@ def GetMdpaFileName(self) -> str: return "solid" def test_GetControlField(self): - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(self.implicit_shape_control.GetControlField()), 213.27526425126743, 4) - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(self.explicit_shape_control.GetControlField()), 0.0000, 4) + self.assertAlmostEqual(numpy.linalg.norm(self.implicit_shape_control.GetControlField().data), 213.27526425126743, 4) + self.assertAlmostEqual(numpy.linalg.norm(self.explicit_shape_control.GetControlField().data), 0.0000, 4) def test_GetPhysicalField(self): shape_field = self.explicit_shape_control.GetPhysicalField() - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(shape_field), 4.24264068711927, 10) + self.assertAlmostEqual(numpy.linalg.norm(shape_field.data), 4.24264068711927, 10) shape_field = self.implicit_shape_control.GetPhysicalField() - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(shape_field), 4.24264068711927, 10) + self.assertAlmostEqual(numpy.linalg.norm(shape_field.data), 4.24264068711927, 10) def test_MapGradient(self): - constant_field_value = Kratos.Array3([1.0, 1.0, 1.0]) - solid_physical_gradient = self.explicit_shape_control.GetEmptyField() - Kratos.Expression.LiteralExpressionIO.SetData(solid_physical_gradient, constant_field_value) + solid_physical_gradient.data[:] = 1.0 mapped_gradient = self.explicit_shape_control.MapGradient({KratosOA.SHAPE: solid_physical_gradient}) - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(mapped_gradient), 13.52774925846869, 10) + self.assertAlmostEqual(numpy.linalg.norm(mapped_gradient.data), 13.52774925846869, 10) solid_physical_gradient = self.implicit_shape_control.GetEmptyField() - Kratos.Expression.LiteralExpressionIO.SetData(solid_physical_gradient, constant_field_value) + solid_physical_gradient.data[:] = 1.0 mapped_gradient = self.implicit_shape_control.MapGradient({KratosOA.SHAPE: solid_physical_gradient}) - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(mapped_gradient), 20.108624626448545, 10) + self.assertAlmostEqual(numpy.linalg.norm(mapped_gradient.data), 20.108624626448545, 10) def test_UpdateExplicit(self): - constant_field_value = Kratos.Array3([0.1, 0.1, 0.1]) - update_field = self.explicit_shape_control.GetEmptyField() - Kratos.Expression.LiteralExpressionIO.SetData(update_field, constant_field_value) + update_field.data[:] = 0.1 self.explicit_shape_control.Update(update_field) control_field = self.explicit_shape_control.GetControlField() shape_field = self.explicit_shape_control.GetPhysicalField() - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(control_field), 0.6480740698407862, 10) - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(shape_field), 4.524378410345448, 10) + self.assertAlmostEqual(numpy.linalg.norm(control_field.data), 0.6480740698407862, 10) + self.assertAlmostEqual(numpy.linalg.norm(shape_field.data), 4.524378410345448, 10) def test_UpdateImplicit(self): - constant_field_value = Kratos.Array3([0.1, 0.1, 0.1]) update_field = self.implicit_shape_control.GetEmptyField() - Kratos.Expression.LiteralExpressionIO.SetData(update_field, constant_field_value) + update_field.data[:] = 0.1 self.implicit_shape_control.Update(update_field) control_field = self.implicit_shape_control.GetControlField() shape_field = self.implicit_shape_control.GetPhysicalField() - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(control_field), 0.6480740698407862, 10) - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(shape_field), 4.370590586296503, 10) + self.assertAlmostEqual(numpy.linalg.norm(control_field.data), 0.6480740698407862, 10) + self.assertAlmostEqual(numpy.linalg.norm(shape_field.data), 4.370590586296503, 10) if __name__ == "__main__": kratos_unittest.main() From 7924e012ee0011329dd05b7b1f8a770bf320b60d Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 6 Feb 2026 08:18:42 +0100 Subject: [PATCH 053/116] update shell thickness control --- .../thickness/shell_thickness_control.py | 61 ++++++++++--------- .../thickness/test_shell_thickness_control.py | 61 ++++++++++--------- 2 files changed, 62 insertions(+), 60 deletions(-) diff --git a/applications/OptimizationApplication/python_scripts/controls/thickness/shell_thickness_control.py b/applications/OptimizationApplication/python_scripts/controls/thickness/shell_thickness_control.py index 639c7bb624fc..1344d649f87e 100644 --- a/applications/OptimizationApplication/python_scripts/controls/thickness/shell_thickness_control.py +++ b/applications/OptimizationApplication/python_scripts/controls/thickness/shell_thickness_control.py @@ -1,11 +1,10 @@ +import numpy from typing import Optional import KratosMultiphysics as Kratos import KratosMultiphysics.OptimizationApplication as KratosOA from KratosMultiphysics.OptimizationApplication.controls.control import Control -from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import ContainerExpressionTypes from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes -from KratosMultiphysics.OptimizationApplication.utilities.helper_utilities import IsSameContainerExpression from KratosMultiphysics.OptimizationApplication.utilities.model_part_utilities import ModelPartOperation from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import TimeLogger from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView @@ -81,8 +80,8 @@ def Initialize(self) -> None: # initialize the projections self.thickness_projection.SetProjectionSpaces(self.filtered_thicknesses, self.physical_thicknesses) - physical_thickness_field = Kratos.Expression.ElementExpression(self.model_part) - KratosOA.PropertiesVariableExpressionIO.Read(physical_thickness_field, Kratos.THICKNESS) + physical_thickness_field = KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(self.model_part.Elements, Kratos.THICKNESS) + physical_thickness_field.CollectData() # project backward the uniform physical control field and assign it to the control field self.physical_phi_field = self.thickness_projection.ProjectBackward(physical_thickness_field) @@ -102,47 +101,49 @@ def Finalize(self) -> None: def GetPhysicalKratosVariables(self) -> 'list[SupportedSensitivityFieldVariableTypes]': return [Kratos.THICKNESS] - def GetEmptyField(self) -> ContainerExpressionTypes: - field = Kratos.Expression.ElementExpression(self.model_part) - Kratos.Expression.LiteralExpressionIO.SetData(field, 0.0) + def GetEmptyField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + field = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Elements, Kratos.THICKNESS) + field.data[:] = 0.0 return field - def GetControlField(self) -> ContainerExpressionTypes: - return self.control_phi_field + def GetControlField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + return Kratos.TensorAdaptors.DoubleTensorAdaptor(self.control_phi_field) - def GetPhysicalField(self) -> ContainerExpressionTypes: - physical_thickness_field = Kratos.Expression.ElementExpression(self.model_part) - KratosOA.PropertiesVariableExpressionIO.Read(physical_thickness_field, Kratos.THICKNESS) + def GetPhysicalField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + physical_thickness_field = KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(self.model_part.Elements, Kratos.THICKNESS) + physical_thickness_field.CollectData() return physical_thickness_field - def MapGradient(self, physical_gradient_variable_container_expression_map: 'dict[SupportedSensitivityFieldVariableTypes, ContainerExpressionTypes]') -> ContainerExpressionTypes: + def MapGradient(self, physical_gradient_variable_tensor_adaptor_map: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleTensorAdaptor]') -> Kratos.TensorAdaptors.DoubleTensorAdaptor: with TimeLogger("ShellThicknessControl::MapGradient", None, "Finished",False): - keys = physical_gradient_variable_container_expression_map.keys() + keys = physical_gradient_variable_tensor_adaptor_map.keys() if len(keys) != 1: raise RuntimeError(f"Provided more than required gradient fields for control \"{self.GetName()}\". Following are the variables:\n\t" + "\n\t".join([k.Name() for k in keys])) if Kratos.THICKNESS not in keys: raise RuntimeError(f"The required gradient for control \"{self.GetName()}\" w.r.t. {Kratos.THICKNESS.Name()} not found. Followings are the variables:\n\t" + "\n\t".join([k.Name() for k in keys])) - physical_gradient = physical_gradient_variable_container_expression_map[Kratos.THICKNESS] - if not IsSameContainerExpression(physical_gradient, self.GetEmptyField()): + physical_gradient = physical_gradient_variable_tensor_adaptor_map[Kratos.THICKNESS] + if physical_gradient.GetContainer() != self.model_part.Elements: raise RuntimeError(f"Gradients for the required element container not found for control \"{self.GetName()}\". [ required model part name: {self.model_part.FullName()}, given model part name: {physical_gradient.GetModelPart().FullName()} ]") # multiply the physical sensitivity field with projection derivatives - projected_gradient = physical_gradient * self.projection_derivative_field + projected_gradient = Kratos.TensorAdaptors.DoubleTensorAdaptor(physical_gradient) + projected_gradient.data = physical_gradient.data * self.projection_derivative_field.data # now filter the field filtered_gradient = self.filter.BackwardFilterIntegratedField(projected_gradient) return filtered_gradient - def Update(self, new_control_field: ContainerExpressionTypes) -> bool: - if not IsSameContainerExpression(new_control_field, self.GetEmptyField()): + def Update(self, new_control_field: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> bool: + if new_control_field.GetContainer() != self.model_part.Elements: raise RuntimeError(f"Updates for the required element container not found for control \"{self.GetName()}\". [ required model part name: {self.model_part.FullName()}, given model part name: {new_control_field.GetModelPart().FullName()} ]") - update = new_control_field - self.control_phi_field - if Kratos.Expression.Utils.NormL2(update) > 1e-15: + update = Kratos.TensorAdaptors.DoubleTensorAdaptor(new_control_field) + update.data[:] = new_control_field.data - self.control_phi_field.data + if numpy.linalg.norm(update.data) > 1e-15: with TimeLogger(self.__class__.__name__, f"Updating {self.GetName()}...", f"Finished updating of {self.GetName()}.",False): # update the control thickness field - self.control_phi_field = new_control_field + self.control_phi_field.data[:] = new_control_field.data # now update the physical field self._UpdateAndOutputFields(update) @@ -154,15 +155,15 @@ def Update(self, new_control_field: ContainerExpressionTypes) -> bool: self.thickness_projection.Update() return False - def _UpdateAndOutputFields(self, update: ContainerExpressionTypes) -> None: + def _UpdateAndOutputFields(self, update: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> None: # filter the control field filtered_thickness_field_update = self.filter.ForwardFilterField(update) - self.physical_phi_field = Kratos.Expression.Utils.Collapse(self.physical_phi_field + filtered_thickness_field_update) + self.physical_phi_field.data += filtered_thickness_field_update.data # project forward the filtered thickness field projected_filtered_thickness_field = self.thickness_projection.ProjectForward(self.physical_phi_field) # now update physical field - KratosOA.PropertiesVariableExpressionIO.Write(projected_filtered_thickness_field, Kratos.THICKNESS) + KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(projected_filtered_thickness_field, Kratos.THICKNESS, copy=False).StoreData() if self.consider_recursive_property_update: KratosOA.OptimizationUtils.UpdatePropertiesVariableWithRootValueRecursively(projected_filtered_thickness_field.GetContainer(), Kratos.THICKNESS) @@ -171,12 +172,12 @@ def _UpdateAndOutputFields(self, update: ContainerExpressionTypes) -> None: # now output the fields un_buffered_data = ComponentDataView(self, self.optimization_problem).GetUnBufferedData() - un_buffered_data.SetValue("physical_thickness", projected_filtered_thickness_field.Clone(),overwrite=True) + un_buffered_data.SetValue("physical_thickness", projected_filtered_thickness_field,overwrite=True) if self.output_all_fields: - un_buffered_data.SetValue("filtered_thickness_update", filtered_thickness_field_update.Clone(), overwrite=True) - un_buffered_data.SetValue("control_thickness_phi", self.control_phi_field.Clone(), overwrite=True) - un_buffered_data.SetValue("physical_thickness_phi", self.physical_phi_field.Clone(), overwrite=True) - un_buffered_data.SetValue("projection_derivative", self.projection_derivative_field.Clone(), overwrite=True) + un_buffered_data.SetValue("filtered_thickness_update", filtered_thickness_field_update, overwrite=True) + un_buffered_data.SetValue("control_thickness_phi", Kratos.TensorAdaptors.DoubleTensorAdaptor(self.control_phi_field), overwrite=True) + un_buffered_data.SetValue("physical_thickness_phi", Kratos.TensorAdaptors.DoubleTensorAdaptor(self.physical_phi_field), overwrite=True) + un_buffered_data.SetValue("projection_derivative", Kratos.TensorAdaptors.DoubleTensorAdaptor(self.projection_derivative_field), overwrite=True) def __str__(self) -> str: return f"Control [type = {self.__class__.__name__}, name = {self.GetName()}, model part name = {self.model_part.FullName()}, control variable = {Kratos.THICKNESS.Name()}" diff --git a/applications/OptimizationApplication/tests/control/thickness/test_shell_thickness_control.py b/applications/OptimizationApplication/tests/control/thickness/test_shell_thickness_control.py index 526bed8a917a..cb635a1d0432 100644 --- a/applications/OptimizationApplication/tests/control/thickness/test_shell_thickness_control.py +++ b/applications/OptimizationApplication/tests/control/thickness/test_shell_thickness_control.py @@ -1,4 +1,5 @@ +import numpy import KratosMultiphysics as Kratos import KratosMultiphysics.OptimizationApplication as KratosOA @@ -51,41 +52,41 @@ def setUpClass(cls): Kratos.ReadMaterialsUtility(cls.model).ReadMaterials(material_params) cls.thickness_control.Initialize() - cls.initial_thickness = Kratos.Expression.ElementExpression(cls.model_part) - KratosOA.PropertiesVariableExpressionIO.Read(cls.initial_thickness, Kratos.THICKNESS) + cls.initial_thickness = KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(cls.model_part.Elements, Kratos.THICKNESS) + cls.initial_thickness.CollectData() def setUp(self) -> None: - KratosOA.PropertiesVariableExpressionIO.Write(self.initial_thickness, Kratos.THICKNESS) + self.initial_thickness.StoreData() @classmethod def tearDownClass(cls): with kratos_unittest.WorkFolderScope(".", __file__): DeleteFileIfExisting("Thick_2x2_Shell.time") - def test_GetControlField(self): - control_field = self.thickness_control.GetControlField() - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(control_field), 0.5, 4) - - def test_GetPhysicalField(self): - thickness_field = self.thickness_control.GetPhysicalField() - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(thickness_field), 0.03, 4) - - def test_MapGradient(self): - physical_gradient = self.thickness_control.GetEmptyField() - for element in physical_gradient.GetContainer(): - element.SetValue(KratosOA.THICKNESS_SENSITIVITY, element.GetGeometry().DomainSize()) - Kratos.Expression.VariableExpressionIO.Read(physical_gradient, KratosOA.THICKNESS_SENSITIVITY) - mapped_gradient = self.thickness_control.MapGradient({Kratos.THICKNESS: physical_gradient}) - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(mapped_gradient), 0.5625, 4) - - def test_Update(self): - update_field = self.thickness_control.GetEmptyField() - Kratos.Expression.LiteralExpressionIO.SetData(update_field, 0.75) - self.thickness_control.Update(update_field) - control_field = self.thickness_control.GetControlField() - thickness_field = self.thickness_control.GetPhysicalField() - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(control_field), 0.75, 4) - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(thickness_field), 0.019999962733607157, 10) + # def test_GetControlField(self): + # control_field = self.thickness_control.GetControlField() + # self.assertAlmostEqual(numpy.linalg.norm(control_field.data, ord=numpy.inf), 0.35, 4) + + # def test_GetPhysicalField(self): + # thickness_field = self.thickness_control.GetPhysicalField() + # self.assertAlmostEqual(numpy.linalg.norm(thickness_field.data), 0.03, 4) + + # def test_MapGradient(self): + # physical_gradient = self.thickness_control.GetEmptyField() + # for element in physical_gradient.GetContainer(): + # element.SetValue(KratosOA.THICKNESS_SENSITIVITY, element.GetGeometry().DomainSize()) + # Kratos.TensorAdaptors.VariableTensorAdaptor(physical_gradient, KratosOA.THICKNESS_SENSITIVITY, copy=False).CollectData() + # mapped_gradient = self.thickness_control.MapGradient({Kratos.THICKNESS: physical_gradient}) + # self.assertAlmostEqual(numpy.linalg.norm(mapped_gradient.data), 0.5625, 4) + + # def test_Update(self): + # update_field = self.thickness_control.GetEmptyField() + # update_field.data[:] = 0.75 + # self.thickness_control.Update(update_field) + # control_field = self.thickness_control.GetControlField() + # thickness_field = self.thickness_control.GetPhysicalField() + # self.assertAlmostEqual(numpy.linalg.norm(control_field.data, ord=numpy.inf), 0.75, 4) + # self.assertAlmostEqual(numpy.linalg.norm(thickness_field.data, ord=numpy.inf), 0.019999999998375886, 10) def test_AdaptiveBeta(self): parameters = Kratos.Parameters("""{ @@ -110,12 +111,12 @@ def test_AdaptiveBeta(self): control_field = thickness_control.GetControlField() thickness_control.Update(control_field) for i in range(20): - control_field *= 1.2 - thickness_control.Update(control_field) + control_field.data *= 1.2 + self.assertTrue(thickness_control.Update(control_field), msg=f"Failed at iteration = {i} with update = {control_field.data}, control_field = {thickness_control.GetControlField().data}") self.optimization_problem.AdvanceStep() self.assertAlmostEqual(thickness_control.thickness_projection.beta, 0.014071004226562506) - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(thickness_control.GetPhysicalField()), 0.031423121954655735) + self.assertAlmostEqual(numpy.linalg.norm(thickness_control.GetPhysicalField().data), 0.03204326420888321) if __name__ == "__main__": kratos_unittest.main() \ No newline at end of file From 9eee672751dac821dd65dffb73f283a7a112b6ce Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 6 Feb 2026 08:23:38 +0100 Subject: [PATCH 054/116] remove unnecessary tests --- ...ic_centroid_deviation_response_function.py | 1 - .../utilities/model_part_utilities.py | 117 ------------------ .../tests/test_OptimizationApplication.py | 9 -- .../tests/test_OptimizationApplication_mpi.py | 8 -- .../tests/test_model_part_utils.py | 75 ----------- 5 files changed, 210 deletions(-) delete mode 100644 applications/OptimizationApplication/python_scripts/utilities/model_part_utilities.py diff --git a/applications/OptimizationApplication/python_scripts/responses/geometric_centroid_deviation_response_function.py b/applications/OptimizationApplication/python_scripts/responses/geometric_centroid_deviation_response_function.py index 5b28518775db..61d4ccec9863 100644 --- a/applications/OptimizationApplication/python_scripts/responses/geometric_centroid_deviation_response_function.py +++ b/applications/OptimizationApplication/python_scripts/responses/geometric_centroid_deviation_response_function.py @@ -5,7 +5,6 @@ from KratosMultiphysics.OptimizationApplication.responses.response_function import ResponseFunction from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes from KratosMultiphysics.OptimizationApplication.utilities.model_part_utilities import ModelPartOperation -from KratosMultiphysics.OptimizationApplication.utilities.model_part_utilities import ModelPartUtilities def Factory(model: Kratos.Model, parameters: Kratos.Parameters, _) -> ResponseFunction: if not parameters.Has("name"): diff --git a/applications/OptimizationApplication/python_scripts/utilities/model_part_utilities.py b/applications/OptimizationApplication/python_scripts/utilities/model_part_utilities.py deleted file mode 100644 index e0bf9335f05c..000000000000 --- a/applications/OptimizationApplication/python_scripts/utilities/model_part_utilities.py +++ /dev/null @@ -1,117 +0,0 @@ -from typing import Any -from enum import Enum -import KratosMultiphysics as Kratos -import KratosMultiphysics.OptimizationApplication as KratosOA - -class ModelPartOperation: - class OperationType(Enum): - UNION = 1, - INTERSECT = 2 - - def __init__(self, model: Kratos.Model, operation_type: OperationType, suggested_model_part_name: str, list_of_operation_model_part_full_names: 'list[str]', add_neighbours: bool) -> None: - self.model = model - self.operation_type = operation_type - self.suggested_model_part_name = suggested_model_part_name - self.list_of_operation_model_part_full_names = sorted(list(set(list_of_operation_model_part_full_names))) - self.add_neighbours = add_neighbours - - if len(list_of_operation_model_part_full_names) == 0: - raise RuntimeError("No operating model part names are provided.") - - if suggested_model_part_name.find("#") != -1 or any([mp_name.find("#") != -1 for mp_name in list_of_operation_model_part_full_names]): - # find '#' in the model part names which is not allowed. - raise RuntimeError(f"The model part names cannot contain '#' character. Parsed model part names are as followings:\n\t suggested model part name: \"{suggested_model_part_name}\"\n\toperation model part names:\n\t" + "\n\t\t".join(list_of_operation_model_part_full_names)) - - # set the root model part. This needs to always exist. - self.root_model_part = self.model[self.list_of_operation_model_part_full_names[0].split(".")[0]] - self.status_msg = "" - - def GetRootModelPart(self) -> Kratos.ModelPart: - return self.root_model_part - - def GetModelPartFullName(self) -> str: - # check whether is there a need to perform binary operations - if self.operation_type == ModelPartOperation.OperationType.UNION or self.operation_type == ModelPartOperation.OperationType.INTERSECT: - if len(self.list_of_operation_model_part_full_names) == 1: - # all the operation model parts are the same, hence no need of doing an operation. - self.status_msg = "" - return self.list_of_operation_model_part_full_names[0] - - # now check in the status messages of the root model part whether this operation is already added. - status_msg_prefix = "ModelPartUtilities_created#" - status_msg_suffix = f"#{self.operation_type.name}#{self.add_neighbours:d}#" + "#".join(self.list_of_operation_model_part_full_names) - status_msg_log = KratosOA.OptAppModelPartUtils.GetModelPartStatusLog(self.GetRootModelPart()) - for status_msg in status_msg_log: - if status_msg.startswith(status_msg_prefix) and status_msg.endswith(status_msg_suffix): - # found the same operation done on a different model part, hence sending that name - self.status_msg = status_msg - full_model_part_name = f"{self.GetRootModelPart().FullName()}.{status_msg.split('#')[1]}" - Kratos.Logger.PrintInfo("ModelPartUtilities", f"Using \"{full_model_part_name}\" with the same operation instead of suggested model part with name = \"{self.GetRootModelPart().FullName()}.{self.suggested_model_part_name}\".") - return full_model_part_name - - # it is not already called for creation. Then put that in the status msg. - if self.root_model_part.HasSubModelPart(self.suggested_model_part_name): - # this means, it already has a model part with suggested name, but - # it does not match the operation identifier. So throw an error - raise RuntimeError(f"Found an already existing submodel part named \"{self.suggested_model_part_name}\" in {self.root_model_part.FullName()} without the required operation identifier = \"{status_msg_suffix}\".") - - self.status_msg = f"{status_msg_prefix}{self.suggested_model_part_name}{status_msg_suffix}" - KratosOA.OptAppModelPartUtils.LogModelPartStatus(self.GetRootModelPart(), self.status_msg) - return f"{self.GetRootModelPart().FullName()}.{self.suggested_model_part_name}" - - def GetModelPart(self) -> Kratos.ModelPart: - model_part_name = self.GetModelPartFullName() - if self.status_msg == "" or self.model.HasModelPart(model_part_name): - # if it is already there, that means it is already created. Hence return it or - # if the self.status_msg == "" means, there is no need to do any model part operations. - # therefore the model part should exist already. - return self.model[model_part_name] - else: - # the model part with the required operation not found. Hence creating it. - sub_model_part = self.model.CreateModelPart(model_part_name) - # now fill the submodel part - operation_model_parts = [self.model[name] for name in self.list_of_operation_model_part_full_names] - if self.operation_type == ModelPartOperation.OperationType.UNION: - Kratos.ModelPartOperationUtilities.Union(sub_model_part, self.root_model_part, operation_model_parts, self.add_neighbours) - elif self.operation_type == ModelPartOperation.OperationType.INTERSECT: - Kratos.ModelPartOperationUtilities.Intersect(sub_model_part, self.root_model_part, operation_model_parts, self.add_neighbours) - - Kratos.Logger.PrintInfo("ModelPartUtilities", f"Created sub model part \"{sub_model_part.FullName()}\".") - - return sub_model_part - -class ModelPartUtilities: - @staticmethod - def __GenerateUniqueIdentifier(prefix: str, list_of_names: 'list[str]', add_neighbours: bool) -> str: - if not all([name.find("#") == -1 for name in list_of_names]): - raise RuntimeError(f"The provided model part names has \"#\" which is invalid. Please remove all occurances of \"#\" character. Provided model part names:\n\t" + "\n\t".join(list_of_names)) - - sorted_names = sorted(list_of_names) - post_fix = "IN" if add_neighbours else "EN" - return (f"{prefix}_{post_fix}_" + "_".join(sorted_names)).replace(".", "-") - - @staticmethod - def GetMergedMap(input_dict: 'dict[Any, KratosOA.CollectiveExpression]', add_neghbours: bool) -> 'dict[Any, Kratos.ModelPart]': - result: 'dict[Any, Kratos.ModelPart]' = {} - for k, v in input_dict.items(): - merging_model_part_names = [container_expression.GetModelPart().FullName() for container_expression in v.GetContainerExpressions()] - - if not merging_model_part_names: - raise RuntimeError("Merging requires atleast one model part.") - - uniqe_identifier_name = ModelPartUtilities.__GenerateUniqueIdentifier("UNION", merging_model_part_names, add_neghbours) - merged_model_part = ModelPartOperation(v.GetContainerExpressions()[0].GetModelPart().GetModel(), ModelPartOperation.OperationType.UNION, uniqe_identifier_name, merging_model_part_names, add_neghbours).GetModelPart() - result[k] = merged_model_part - - return result - - @staticmethod - def GetIntersectedMap(main_model_part: Kratos.ModelPart, input_dict: 'dict[Any, Kratos.ModelPart]', add_neghbours: bool) -> 'dict[Any, Kratos.ModelPart]': - result: 'dict[Any, Kratos.ModelPart]' = {} - for k, v in input_dict.items(): - intersecting_model_part_names = [main_model_part.FullName(), v.FullName()] - uniqe_identifier_name = ModelPartUtilities.__GenerateUniqueIdentifier("INTERSECT", intersecting_model_part_names, add_neghbours) - intersected_model_part = ModelPartOperation(main_model_part.GetModel(), ModelPartOperation.OperationType.INTERSECT, uniqe_identifier_name, intersecting_model_part_names, add_neghbours).GetModelPart() - result[k] = intersected_model_part - - return result \ No newline at end of file diff --git a/applications/OptimizationApplication/tests/test_OptimizationApplication.py b/applications/OptimizationApplication/tests/test_OptimizationApplication.py index 68f1c4bd91d7..023de4379e4c 100644 --- a/applications/OptimizationApplication/tests/test_OptimizationApplication.py +++ b/applications/OptimizationApplication/tests/test_OptimizationApplication.py @@ -32,9 +32,6 @@ import test_model_part_utils import test_model_part_controllers import test_connectivity_preserving_model_part_controller -import test_container_expression_utils -import test_container_expression -import test_collective_expressions import test_sigmoidal_projection import test_buffered_dict import control.test_master_control @@ -88,9 +85,7 @@ def AssembleTestSuites(): smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_optimization_info.TestOptimizationInfo])) smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_optimization_utils.TestOptimizationUtils])) smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_model_part_utils.TestOptAppModelPartUtils])) - smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_model_part_utils.TestModelPartUtilities])) smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_response_utilities.TestResponseUtilities])) - smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_container_expression_utils.TestContainerExpressionUtils])) smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([responses_tests.test_response_routine.TestResponseRoutine])) smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([responses_tests.test_standardized_responses.TestStandardizedObjective])) @@ -106,10 +101,6 @@ def AssembleTestSuites(): smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([responses_tests.test_discrete_value_residual_response_function.TestDiscreteValueResidualResponseFunctionLogarithm])) smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_external_response_function.TestExternalResponseFunction])) - smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_container_expression.TestConditionPropertiesExpression])) - smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_container_expression.TestElementPropertiesExpression])) - smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_collective_expressions.TestCollectiveExpressions])) - smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_sigmoidal_projection.TestSigmoidalProjection])) smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_model_part_controllers.TestMdpaModelPartController])) diff --git a/applications/OptimizationApplication/tests/test_OptimizationApplication_mpi.py b/applications/OptimizationApplication/tests/test_OptimizationApplication_mpi.py index cf56e1d34707..4b52c099053f 100644 --- a/applications/OptimizationApplication/tests/test_OptimizationApplication_mpi.py +++ b/applications/OptimizationApplication/tests/test_OptimizationApplication_mpi.py @@ -9,9 +9,6 @@ # Import the tests or test_classes to create the suits import test_model_part_utils -import test_container_expression_utils -import test_container_expression -import test_collective_expressions import process_tests.test_optimization_problem_ascii_output_process def AssembleTestSuites(): @@ -33,11 +30,6 @@ def AssembleTestSuites(): # adding custom process tests smallMPISuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_model_part_utils.TestOptAppModelPartUtils])) - smallMPISuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_container_expression_utils.TestContainerExpressionUtils])) - - smallMPISuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_container_expression.TestConditionPropertiesExpression])) - smallMPISuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_container_expression.TestElementPropertiesExpression])) - smallMPISuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_collective_expressions.TestCollectiveExpressions])) smallMPISuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([process_tests.test_optimization_problem_ascii_output_process.TestOptimizationProblemAsciiOutputProcess])) diff --git a/applications/OptimizationApplication/tests/test_model_part_utils.py b/applications/OptimizationApplication/tests/test_model_part_utils.py index df9c3814ead1..647ef192b775 100644 --- a/applications/OptimizationApplication/tests/test_model_part_utils.py +++ b/applications/OptimizationApplication/tests/test_model_part_utils.py @@ -1,12 +1,9 @@ -import random - import KratosMultiphysics as Kratos import KratosMultiphysics.OptimizationApplication as KratosOA # Import KratosUnittest import KratosMultiphysics.KratosUnittest as kratos_unittest from KratosMultiphysics.testing.utilities import ReadModelPart -from KratosMultiphysics.OptimizationApplication.utilities.model_part_utilities import ModelPartOperation class TestOptAppModelPartUtils(kratos_unittest.TestCase): @classmethod @@ -232,77 +229,5 @@ def test_ClearEntitiesOfModelPartsWithCommonReferenceEntitiesBetweenReferenceLis self.assertTrue(self.model.HasModelPart("test.evaluated_element_2._Nodes_NoConditions_NoElements_NoParents_ExaminedMPs_test>sensitivity_condition_1;test>sensitivity_element_1;test>sensitivity_element_2;test>sensitivity_element_3;test>sensitivity_element_4;")) self.assertTrue(self.model.HasModelPart("test.evaluated_element_3._Nodes_NoConditions_NoElements_NoParents_ExaminedMPs_test>sensitivity_condition_1;test>sensitivity_element_1;test>sensitivity_element_2;test>sensitivity_element_3;test>sensitivity_element_4;")) -class TestModelPartUtilities(kratos_unittest.TestCase): - @classmethod - def setUpClass(cls) -> None: - cls.model = Kratos.Model() - cls.model_part = cls.model.CreateModelPart("test") - - cls.sub_model_part_names_list: 'list[str]' = [] - cls.sub_model_part_names_list.append(cls.model_part.CreateSubModelPart("sub_1").FullName()) - cls.sub_model_part_names_list.append(cls.model_part.CreateSubModelPart("sub_2").FullName()) - cls.sub_model_part_names_list.append(cls.model_part.CreateSubModelPart("sub_3").FullName()) - - def test_GetModelPartFullName(self): - dummy_names = ["test.sub_full_name_1", "test.sub_full_name_2", "test.sub_full_name_3", "test.sub_full_name_4"] - mp_operation_1 = ModelPartOperation(self.model, ModelPartOperation.OperationType.UNION, "full_name_t1", dummy_names, False) - self.assertEqual(mp_operation_1.GetModelPartFullName(), "test.full_name_t1") - - random.shuffle(dummy_names) - mp_operation_2 = ModelPartOperation(self.model, ModelPartOperation.OperationType.UNION, "full_name_t2", dummy_names, False) - self.assertEqual(mp_operation_2.GetModelPartFullName(), "test.full_name_t1") - - random.shuffle(dummy_names) - mp_operation_3 = ModelPartOperation(self.model, ModelPartOperation.OperationType.UNION, "full_name_t3", dummy_names, True) - self.assertEqual(mp_operation_3.GetModelPartFullName(), "test.full_name_t3") - - random.shuffle(dummy_names) - mp_operation_3 = ModelPartOperation(self.model, ModelPartOperation.OperationType.INTERSECT, "full_name_t4", dummy_names, True) - self.assertEqual(mp_operation_3.GetModelPartFullName(), "test.full_name_t4") - - random.shuffle(dummy_names) - mp_operation_3 = ModelPartOperation(self.model, ModelPartOperation.OperationType.INTERSECT, "full_name_t5", dummy_names, True) - self.assertEqual(mp_operation_3.GetModelPartFullName(), "test.full_name_t4") - - random.shuffle(dummy_names) - mp_operation_3 = ModelPartOperation(self.model, ModelPartOperation.OperationType.INTERSECT, "full_name_t6", dummy_names, True) - self.assertEqual(mp_operation_3.GetModelPartFullName(), "test.full_name_t4") - - random.shuffle(dummy_names) - mp_operation_3 = ModelPartOperation(self.model, ModelPartOperation.OperationType.UNION, "full_name_t6", dummy_names, True) - self.assertEqual(mp_operation_3.GetModelPartFullName(), "test.full_name_t3") - - def test_UnionNoOperation(self): - _ = ModelPartOperation(self.model, ModelPartOperation.OperationType.UNION, "t1", [self.model_part.FullName()], False).GetModelPart() - self.assertFalse(self.model_part.HasSubModelPart("t1")) - - def test_IntersectNoOperation(self): - _ = ModelPartOperation(self.model, ModelPartOperation.OperationType.INTERSECT, "t2", [self.model_part.FullName()], False).GetModelPart() - self.assertFalse(self.model_part.HasSubModelPart("t2")) - - def test_UnionOperation(self): - random.shuffle(self.sub_model_part_names_list) - _ = ModelPartOperation(self.model, ModelPartOperation.OperationType.UNION, "t3", self.sub_model_part_names_list, False).GetModelPart() - self.assertTrue(self.model_part.HasSubModelPart("t3")) - - random.shuffle(self.sub_model_part_names_list) - model_part = ModelPartOperation(self.model, ModelPartOperation.OperationType.UNION, "t4", self.sub_model_part_names_list, False).GetModelPart() - self.assertFalse(self.model_part.HasSubModelPart("t4")) - - random.shuffle(self.sub_model_part_names_list) - self.assertEqual(model_part, ModelPartOperation(self.model, ModelPartOperation.OperationType.UNION, "t5", self.sub_model_part_names_list, False).GetModelPart()) - - def test_IntersectNoOperation(self): - random.shuffle(self.sub_model_part_names_list) - _ = ModelPartOperation(self.model, ModelPartOperation.OperationType.INTERSECT, "t5", self.sub_model_part_names_list, False).GetModelPart() - self.assertTrue(self.model_part.HasSubModelPart("t5")) - - random.shuffle(self.sub_model_part_names_list) - model_part = ModelPartOperation(self.model, ModelPartOperation.OperationType.INTERSECT, "t6", self.sub_model_part_names_list, False).GetModelPart() - self.assertFalse(self.model_part.HasSubModelPart("t6")) - - random.shuffle(self.sub_model_part_names_list) - self.assertEqual(model_part, ModelPartOperation(self.model, ModelPartOperation.OperationType.INTERSECT, "t7", self.sub_model_part_names_list, False).GetModelPart()) - if __name__ == "__main__": kratos_unittest.main() \ No newline at end of file From eaa90acbdc6c9663c39086274f6a156d28f8248a Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 6 Feb 2026 08:26:35 +0100 Subject: [PATCH 055/116] Revert "remove unnecessary tests" This reverts commit 9eee672751dac821dd65dffb73f283a7a112b6ce. --- ...ic_centroid_deviation_response_function.py | 1 + .../utilities/model_part_utilities.py | 117 ++++++++++++++++++ .../tests/test_OptimizationApplication.py | 9 ++ .../tests/test_OptimizationApplication_mpi.py | 8 ++ .../tests/test_model_part_utils.py | 75 +++++++++++ 5 files changed, 210 insertions(+) create mode 100644 applications/OptimizationApplication/python_scripts/utilities/model_part_utilities.py diff --git a/applications/OptimizationApplication/python_scripts/responses/geometric_centroid_deviation_response_function.py b/applications/OptimizationApplication/python_scripts/responses/geometric_centroid_deviation_response_function.py index 61d4ccec9863..5b28518775db 100644 --- a/applications/OptimizationApplication/python_scripts/responses/geometric_centroid_deviation_response_function.py +++ b/applications/OptimizationApplication/python_scripts/responses/geometric_centroid_deviation_response_function.py @@ -5,6 +5,7 @@ from KratosMultiphysics.OptimizationApplication.responses.response_function import ResponseFunction from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes from KratosMultiphysics.OptimizationApplication.utilities.model_part_utilities import ModelPartOperation +from KratosMultiphysics.OptimizationApplication.utilities.model_part_utilities import ModelPartUtilities def Factory(model: Kratos.Model, parameters: Kratos.Parameters, _) -> ResponseFunction: if not parameters.Has("name"): diff --git a/applications/OptimizationApplication/python_scripts/utilities/model_part_utilities.py b/applications/OptimizationApplication/python_scripts/utilities/model_part_utilities.py new file mode 100644 index 000000000000..e0bf9335f05c --- /dev/null +++ b/applications/OptimizationApplication/python_scripts/utilities/model_part_utilities.py @@ -0,0 +1,117 @@ +from typing import Any +from enum import Enum +import KratosMultiphysics as Kratos +import KratosMultiphysics.OptimizationApplication as KratosOA + +class ModelPartOperation: + class OperationType(Enum): + UNION = 1, + INTERSECT = 2 + + def __init__(self, model: Kratos.Model, operation_type: OperationType, suggested_model_part_name: str, list_of_operation_model_part_full_names: 'list[str]', add_neighbours: bool) -> None: + self.model = model + self.operation_type = operation_type + self.suggested_model_part_name = suggested_model_part_name + self.list_of_operation_model_part_full_names = sorted(list(set(list_of_operation_model_part_full_names))) + self.add_neighbours = add_neighbours + + if len(list_of_operation_model_part_full_names) == 0: + raise RuntimeError("No operating model part names are provided.") + + if suggested_model_part_name.find("#") != -1 or any([mp_name.find("#") != -1 for mp_name in list_of_operation_model_part_full_names]): + # find '#' in the model part names which is not allowed. + raise RuntimeError(f"The model part names cannot contain '#' character. Parsed model part names are as followings:\n\t suggested model part name: \"{suggested_model_part_name}\"\n\toperation model part names:\n\t" + "\n\t\t".join(list_of_operation_model_part_full_names)) + + # set the root model part. This needs to always exist. + self.root_model_part = self.model[self.list_of_operation_model_part_full_names[0].split(".")[0]] + self.status_msg = "" + + def GetRootModelPart(self) -> Kratos.ModelPart: + return self.root_model_part + + def GetModelPartFullName(self) -> str: + # check whether is there a need to perform binary operations + if self.operation_type == ModelPartOperation.OperationType.UNION or self.operation_type == ModelPartOperation.OperationType.INTERSECT: + if len(self.list_of_operation_model_part_full_names) == 1: + # all the operation model parts are the same, hence no need of doing an operation. + self.status_msg = "" + return self.list_of_operation_model_part_full_names[0] + + # now check in the status messages of the root model part whether this operation is already added. + status_msg_prefix = "ModelPartUtilities_created#" + status_msg_suffix = f"#{self.operation_type.name}#{self.add_neighbours:d}#" + "#".join(self.list_of_operation_model_part_full_names) + status_msg_log = KratosOA.OptAppModelPartUtils.GetModelPartStatusLog(self.GetRootModelPart()) + for status_msg in status_msg_log: + if status_msg.startswith(status_msg_prefix) and status_msg.endswith(status_msg_suffix): + # found the same operation done on a different model part, hence sending that name + self.status_msg = status_msg + full_model_part_name = f"{self.GetRootModelPart().FullName()}.{status_msg.split('#')[1]}" + Kratos.Logger.PrintInfo("ModelPartUtilities", f"Using \"{full_model_part_name}\" with the same operation instead of suggested model part with name = \"{self.GetRootModelPart().FullName()}.{self.suggested_model_part_name}\".") + return full_model_part_name + + # it is not already called for creation. Then put that in the status msg. + if self.root_model_part.HasSubModelPart(self.suggested_model_part_name): + # this means, it already has a model part with suggested name, but + # it does not match the operation identifier. So throw an error + raise RuntimeError(f"Found an already existing submodel part named \"{self.suggested_model_part_name}\" in {self.root_model_part.FullName()} without the required operation identifier = \"{status_msg_suffix}\".") + + self.status_msg = f"{status_msg_prefix}{self.suggested_model_part_name}{status_msg_suffix}" + KratosOA.OptAppModelPartUtils.LogModelPartStatus(self.GetRootModelPart(), self.status_msg) + return f"{self.GetRootModelPart().FullName()}.{self.suggested_model_part_name}" + + def GetModelPart(self) -> Kratos.ModelPart: + model_part_name = self.GetModelPartFullName() + if self.status_msg == "" or self.model.HasModelPart(model_part_name): + # if it is already there, that means it is already created. Hence return it or + # if the self.status_msg == "" means, there is no need to do any model part operations. + # therefore the model part should exist already. + return self.model[model_part_name] + else: + # the model part with the required operation not found. Hence creating it. + sub_model_part = self.model.CreateModelPart(model_part_name) + # now fill the submodel part + operation_model_parts = [self.model[name] for name in self.list_of_operation_model_part_full_names] + if self.operation_type == ModelPartOperation.OperationType.UNION: + Kratos.ModelPartOperationUtilities.Union(sub_model_part, self.root_model_part, operation_model_parts, self.add_neighbours) + elif self.operation_type == ModelPartOperation.OperationType.INTERSECT: + Kratos.ModelPartOperationUtilities.Intersect(sub_model_part, self.root_model_part, operation_model_parts, self.add_neighbours) + + Kratos.Logger.PrintInfo("ModelPartUtilities", f"Created sub model part \"{sub_model_part.FullName()}\".") + + return sub_model_part + +class ModelPartUtilities: + @staticmethod + def __GenerateUniqueIdentifier(prefix: str, list_of_names: 'list[str]', add_neighbours: bool) -> str: + if not all([name.find("#") == -1 for name in list_of_names]): + raise RuntimeError(f"The provided model part names has \"#\" which is invalid. Please remove all occurances of \"#\" character. Provided model part names:\n\t" + "\n\t".join(list_of_names)) + + sorted_names = sorted(list_of_names) + post_fix = "IN" if add_neighbours else "EN" + return (f"{prefix}_{post_fix}_" + "_".join(sorted_names)).replace(".", "-") + + @staticmethod + def GetMergedMap(input_dict: 'dict[Any, KratosOA.CollectiveExpression]', add_neghbours: bool) -> 'dict[Any, Kratos.ModelPart]': + result: 'dict[Any, Kratos.ModelPart]' = {} + for k, v in input_dict.items(): + merging_model_part_names = [container_expression.GetModelPart().FullName() for container_expression in v.GetContainerExpressions()] + + if not merging_model_part_names: + raise RuntimeError("Merging requires atleast one model part.") + + uniqe_identifier_name = ModelPartUtilities.__GenerateUniqueIdentifier("UNION", merging_model_part_names, add_neghbours) + merged_model_part = ModelPartOperation(v.GetContainerExpressions()[0].GetModelPart().GetModel(), ModelPartOperation.OperationType.UNION, uniqe_identifier_name, merging_model_part_names, add_neghbours).GetModelPart() + result[k] = merged_model_part + + return result + + @staticmethod + def GetIntersectedMap(main_model_part: Kratos.ModelPart, input_dict: 'dict[Any, Kratos.ModelPart]', add_neghbours: bool) -> 'dict[Any, Kratos.ModelPart]': + result: 'dict[Any, Kratos.ModelPart]' = {} + for k, v in input_dict.items(): + intersecting_model_part_names = [main_model_part.FullName(), v.FullName()] + uniqe_identifier_name = ModelPartUtilities.__GenerateUniqueIdentifier("INTERSECT", intersecting_model_part_names, add_neghbours) + intersected_model_part = ModelPartOperation(main_model_part.GetModel(), ModelPartOperation.OperationType.INTERSECT, uniqe_identifier_name, intersecting_model_part_names, add_neghbours).GetModelPart() + result[k] = intersected_model_part + + return result \ No newline at end of file diff --git a/applications/OptimizationApplication/tests/test_OptimizationApplication.py b/applications/OptimizationApplication/tests/test_OptimizationApplication.py index 023de4379e4c..68f1c4bd91d7 100644 --- a/applications/OptimizationApplication/tests/test_OptimizationApplication.py +++ b/applications/OptimizationApplication/tests/test_OptimizationApplication.py @@ -32,6 +32,9 @@ import test_model_part_utils import test_model_part_controllers import test_connectivity_preserving_model_part_controller +import test_container_expression_utils +import test_container_expression +import test_collective_expressions import test_sigmoidal_projection import test_buffered_dict import control.test_master_control @@ -85,7 +88,9 @@ def AssembleTestSuites(): smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_optimization_info.TestOptimizationInfo])) smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_optimization_utils.TestOptimizationUtils])) smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_model_part_utils.TestOptAppModelPartUtils])) + smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_model_part_utils.TestModelPartUtilities])) smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_response_utilities.TestResponseUtilities])) + smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_container_expression_utils.TestContainerExpressionUtils])) smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([responses_tests.test_response_routine.TestResponseRoutine])) smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([responses_tests.test_standardized_responses.TestStandardizedObjective])) @@ -101,6 +106,10 @@ def AssembleTestSuites(): smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([responses_tests.test_discrete_value_residual_response_function.TestDiscreteValueResidualResponseFunctionLogarithm])) smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_external_response_function.TestExternalResponseFunction])) + smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_container_expression.TestConditionPropertiesExpression])) + smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_container_expression.TestElementPropertiesExpression])) + smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_collective_expressions.TestCollectiveExpressions])) + smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_sigmoidal_projection.TestSigmoidalProjection])) smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_model_part_controllers.TestMdpaModelPartController])) diff --git a/applications/OptimizationApplication/tests/test_OptimizationApplication_mpi.py b/applications/OptimizationApplication/tests/test_OptimizationApplication_mpi.py index 4b52c099053f..cf56e1d34707 100644 --- a/applications/OptimizationApplication/tests/test_OptimizationApplication_mpi.py +++ b/applications/OptimizationApplication/tests/test_OptimizationApplication_mpi.py @@ -9,6 +9,9 @@ # Import the tests or test_classes to create the suits import test_model_part_utils +import test_container_expression_utils +import test_container_expression +import test_collective_expressions import process_tests.test_optimization_problem_ascii_output_process def AssembleTestSuites(): @@ -30,6 +33,11 @@ def AssembleTestSuites(): # adding custom process tests smallMPISuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_model_part_utils.TestOptAppModelPartUtils])) + smallMPISuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_container_expression_utils.TestContainerExpressionUtils])) + + smallMPISuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_container_expression.TestConditionPropertiesExpression])) + smallMPISuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_container_expression.TestElementPropertiesExpression])) + smallMPISuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_collective_expressions.TestCollectiveExpressions])) smallMPISuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([process_tests.test_optimization_problem_ascii_output_process.TestOptimizationProblemAsciiOutputProcess])) diff --git a/applications/OptimizationApplication/tests/test_model_part_utils.py b/applications/OptimizationApplication/tests/test_model_part_utils.py index 647ef192b775..df9c3814ead1 100644 --- a/applications/OptimizationApplication/tests/test_model_part_utils.py +++ b/applications/OptimizationApplication/tests/test_model_part_utils.py @@ -1,9 +1,12 @@ +import random + import KratosMultiphysics as Kratos import KratosMultiphysics.OptimizationApplication as KratosOA # Import KratosUnittest import KratosMultiphysics.KratosUnittest as kratos_unittest from KratosMultiphysics.testing.utilities import ReadModelPart +from KratosMultiphysics.OptimizationApplication.utilities.model_part_utilities import ModelPartOperation class TestOptAppModelPartUtils(kratos_unittest.TestCase): @classmethod @@ -229,5 +232,77 @@ def test_ClearEntitiesOfModelPartsWithCommonReferenceEntitiesBetweenReferenceLis self.assertTrue(self.model.HasModelPart("test.evaluated_element_2._Nodes_NoConditions_NoElements_NoParents_ExaminedMPs_test>sensitivity_condition_1;test>sensitivity_element_1;test>sensitivity_element_2;test>sensitivity_element_3;test>sensitivity_element_4;")) self.assertTrue(self.model.HasModelPart("test.evaluated_element_3._Nodes_NoConditions_NoElements_NoParents_ExaminedMPs_test>sensitivity_condition_1;test>sensitivity_element_1;test>sensitivity_element_2;test>sensitivity_element_3;test>sensitivity_element_4;")) +class TestModelPartUtilities(kratos_unittest.TestCase): + @classmethod + def setUpClass(cls) -> None: + cls.model = Kratos.Model() + cls.model_part = cls.model.CreateModelPart("test") + + cls.sub_model_part_names_list: 'list[str]' = [] + cls.sub_model_part_names_list.append(cls.model_part.CreateSubModelPart("sub_1").FullName()) + cls.sub_model_part_names_list.append(cls.model_part.CreateSubModelPart("sub_2").FullName()) + cls.sub_model_part_names_list.append(cls.model_part.CreateSubModelPart("sub_3").FullName()) + + def test_GetModelPartFullName(self): + dummy_names = ["test.sub_full_name_1", "test.sub_full_name_2", "test.sub_full_name_3", "test.sub_full_name_4"] + mp_operation_1 = ModelPartOperation(self.model, ModelPartOperation.OperationType.UNION, "full_name_t1", dummy_names, False) + self.assertEqual(mp_operation_1.GetModelPartFullName(), "test.full_name_t1") + + random.shuffle(dummy_names) + mp_operation_2 = ModelPartOperation(self.model, ModelPartOperation.OperationType.UNION, "full_name_t2", dummy_names, False) + self.assertEqual(mp_operation_2.GetModelPartFullName(), "test.full_name_t1") + + random.shuffle(dummy_names) + mp_operation_3 = ModelPartOperation(self.model, ModelPartOperation.OperationType.UNION, "full_name_t3", dummy_names, True) + self.assertEqual(mp_operation_3.GetModelPartFullName(), "test.full_name_t3") + + random.shuffle(dummy_names) + mp_operation_3 = ModelPartOperation(self.model, ModelPartOperation.OperationType.INTERSECT, "full_name_t4", dummy_names, True) + self.assertEqual(mp_operation_3.GetModelPartFullName(), "test.full_name_t4") + + random.shuffle(dummy_names) + mp_operation_3 = ModelPartOperation(self.model, ModelPartOperation.OperationType.INTERSECT, "full_name_t5", dummy_names, True) + self.assertEqual(mp_operation_3.GetModelPartFullName(), "test.full_name_t4") + + random.shuffle(dummy_names) + mp_operation_3 = ModelPartOperation(self.model, ModelPartOperation.OperationType.INTERSECT, "full_name_t6", dummy_names, True) + self.assertEqual(mp_operation_3.GetModelPartFullName(), "test.full_name_t4") + + random.shuffle(dummy_names) + mp_operation_3 = ModelPartOperation(self.model, ModelPartOperation.OperationType.UNION, "full_name_t6", dummy_names, True) + self.assertEqual(mp_operation_3.GetModelPartFullName(), "test.full_name_t3") + + def test_UnionNoOperation(self): + _ = ModelPartOperation(self.model, ModelPartOperation.OperationType.UNION, "t1", [self.model_part.FullName()], False).GetModelPart() + self.assertFalse(self.model_part.HasSubModelPart("t1")) + + def test_IntersectNoOperation(self): + _ = ModelPartOperation(self.model, ModelPartOperation.OperationType.INTERSECT, "t2", [self.model_part.FullName()], False).GetModelPart() + self.assertFalse(self.model_part.HasSubModelPart("t2")) + + def test_UnionOperation(self): + random.shuffle(self.sub_model_part_names_list) + _ = ModelPartOperation(self.model, ModelPartOperation.OperationType.UNION, "t3", self.sub_model_part_names_list, False).GetModelPart() + self.assertTrue(self.model_part.HasSubModelPart("t3")) + + random.shuffle(self.sub_model_part_names_list) + model_part = ModelPartOperation(self.model, ModelPartOperation.OperationType.UNION, "t4", self.sub_model_part_names_list, False).GetModelPart() + self.assertFalse(self.model_part.HasSubModelPart("t4")) + + random.shuffle(self.sub_model_part_names_list) + self.assertEqual(model_part, ModelPartOperation(self.model, ModelPartOperation.OperationType.UNION, "t5", self.sub_model_part_names_list, False).GetModelPart()) + + def test_IntersectNoOperation(self): + random.shuffle(self.sub_model_part_names_list) + _ = ModelPartOperation(self.model, ModelPartOperation.OperationType.INTERSECT, "t5", self.sub_model_part_names_list, False).GetModelPart() + self.assertTrue(self.model_part.HasSubModelPart("t5")) + + random.shuffle(self.sub_model_part_names_list) + model_part = ModelPartOperation(self.model, ModelPartOperation.OperationType.INTERSECT, "t6", self.sub_model_part_names_list, False).GetModelPart() + self.assertFalse(self.model_part.HasSubModelPart("t6")) + + random.shuffle(self.sub_model_part_names_list) + self.assertEqual(model_part, ModelPartOperation(self.model, ModelPartOperation.OperationType.INTERSECT, "t7", self.sub_model_part_names_list, False).GetModelPart()) + if __name__ == "__main__": kratos_unittest.main() \ No newline at end of file From 1c9f83c22532255bd7b500f06386c01fa6d197f5 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 6 Feb 2026 08:27:58 +0100 Subject: [PATCH 056/116] minor --- .../thickness/test_shell_thickness_control.py | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/applications/OptimizationApplication/tests/control/thickness/test_shell_thickness_control.py b/applications/OptimizationApplication/tests/control/thickness/test_shell_thickness_control.py index cb635a1d0432..e5b867e3d4b6 100644 --- a/applications/OptimizationApplication/tests/control/thickness/test_shell_thickness_control.py +++ b/applications/OptimizationApplication/tests/control/thickness/test_shell_thickness_control.py @@ -63,30 +63,30 @@ def tearDownClass(cls): with kratos_unittest.WorkFolderScope(".", __file__): DeleteFileIfExisting("Thick_2x2_Shell.time") - # def test_GetControlField(self): - # control_field = self.thickness_control.GetControlField() - # self.assertAlmostEqual(numpy.linalg.norm(control_field.data, ord=numpy.inf), 0.35, 4) - - # def test_GetPhysicalField(self): - # thickness_field = self.thickness_control.GetPhysicalField() - # self.assertAlmostEqual(numpy.linalg.norm(thickness_field.data), 0.03, 4) - - # def test_MapGradient(self): - # physical_gradient = self.thickness_control.GetEmptyField() - # for element in physical_gradient.GetContainer(): - # element.SetValue(KratosOA.THICKNESS_SENSITIVITY, element.GetGeometry().DomainSize()) - # Kratos.TensorAdaptors.VariableTensorAdaptor(physical_gradient, KratosOA.THICKNESS_SENSITIVITY, copy=False).CollectData() - # mapped_gradient = self.thickness_control.MapGradient({Kratos.THICKNESS: physical_gradient}) - # self.assertAlmostEqual(numpy.linalg.norm(mapped_gradient.data), 0.5625, 4) - - # def test_Update(self): - # update_field = self.thickness_control.GetEmptyField() - # update_field.data[:] = 0.75 - # self.thickness_control.Update(update_field) - # control_field = self.thickness_control.GetControlField() - # thickness_field = self.thickness_control.GetPhysicalField() - # self.assertAlmostEqual(numpy.linalg.norm(control_field.data, ord=numpy.inf), 0.75, 4) - # self.assertAlmostEqual(numpy.linalg.norm(thickness_field.data, ord=numpy.inf), 0.019999999998375886, 10) + def test_GetControlField(self): + control_field = self.thickness_control.GetControlField() + self.assertAlmostEqual(numpy.linalg.norm(control_field.data, ord=numpy.inf), 0.35, 4) + + def test_GetPhysicalField(self): + thickness_field = self.thickness_control.GetPhysicalField() + self.assertAlmostEqual(numpy.linalg.norm(thickness_field.data), 0.03, 4) + + def test_MapGradient(self): + physical_gradient = self.thickness_control.GetEmptyField() + for element in physical_gradient.GetContainer(): + element.SetValue(KratosOA.THICKNESS_SENSITIVITY, element.GetGeometry().DomainSize()) + Kratos.TensorAdaptors.VariableTensorAdaptor(physical_gradient, KratosOA.THICKNESS_SENSITIVITY, copy=False).CollectData() + mapped_gradient = self.thickness_control.MapGradient({Kratos.THICKNESS: physical_gradient}) + self.assertAlmostEqual(numpy.linalg.norm(mapped_gradient.data), 0.5625, 4) + + def test_Update(self): + update_field = self.thickness_control.GetEmptyField() + update_field.data[:] = 0.75 + self.thickness_control.Update(update_field) + control_field = self.thickness_control.GetControlField() + thickness_field = self.thickness_control.GetPhysicalField() + self.assertAlmostEqual(numpy.linalg.norm(control_field.data, ord=numpy.inf), 0.75, 4) + self.assertAlmostEqual(numpy.linalg.norm(thickness_field.data, ord=numpy.inf), 0.019999999998375886, 10) def test_AdaptiveBeta(self): parameters = Kratos.Parameters("""{ From 686e9f2eda9116c8bb2a2cb3901493264748e18e Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 6 Feb 2026 08:35:28 +0100 Subject: [PATCH 057/116] update master control --- .../python_scripts/controls/master_control.py | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/applications/OptimizationApplication/python_scripts/controls/master_control.py b/applications/OptimizationApplication/python_scripts/controls/master_control.py index 0b67b893f7d6..e54d096408ed 100644 --- a/applications/OptimizationApplication/python_scripts/controls/master_control.py +++ b/applications/OptimizationApplication/python_scripts/controls/master_control.py @@ -64,20 +64,20 @@ def GetPhysicalKratosVariableCombinedTensorAdaptorsMap(self) -> 'dict[SupportedS return physical_variable_combined_ta_dict def GetEmptyField(self) -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: - """Returns empty CollectiveExpression containing empty ContainerExpressions for each control. + """Returns empty CombinedTensorAdaptor containing empty TensorAdaptor for each control. Returns: - Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: Empty CollectiveExpression + Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: Empty CombinedTensorAdaptor """ ta = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([control.GetEmptyField() for control in self.__list_of_controls], perform_collect_data_recursively=False, perform_store_data_recursively=False) ta.CollectData() # reading all the data from each ta adaptor to the combined tensor adaptor return ta def GetControlField(self) -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: - """Returns CollectiveExpression containing control field ContainerExpressions for each control. + """Returns CombinedTensorAdaptor containing control field TensorAdaptor for each control. Returns: - Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: Control field CollectiveExpression + Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: Control field CombinedTensorAdaptor """ ta = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([control.GetControlField() for control in self.__list_of_controls], perform_collect_data_recursively=False, perform_store_data_recursively=False) ta.CollectData() # reading all the data from each ta adaptor to the combined tensor adaptor @@ -130,7 +130,7 @@ def MapGradient(self, physical_space_gradient_variable_and_combined_tensor_adapt for control in self.__list_of_controls: # iterate through each control to create its own container map from the combined tensor adaptor map given as input - control_physical_sensitivities_container_expression_map: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleTensorAdaptor]' = {} + control_physical_sensitivities_tensor_adaptor_map: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleTensorAdaptor]' = {} for physical_control_variable in control.GetPhysicalKratosVariables(): # first assume the gradients for this physical_control_variable is zero, hence get the zero valued tensor adaptor. control_ta = control.GetEmptyField() @@ -144,16 +144,16 @@ def MapGradient(self, physical_space_gradient_variable_and_combined_tensor_adapt for ta in sensitivity_cta.GetTensorAdaptors(): if ta.GetContainer() == control_ta.GetContainer(): # there exists for this control's physical variables sensitivities. - control_physical_sensitivities_container_expression_map[physical_control_variable] = ta + control_physical_sensitivities_tensor_adaptor_map[physical_control_variable] = ta break - if physical_control_variable not in control_physical_sensitivities_container_expression_map.keys(): - # If it is found from input gradients, the control_expression will have those values, - # otherwise it will have representative zero control_expression. - control_physical_sensitivities_container_expression_map[physical_control_variable] = control_ta + if physical_control_variable not in control_physical_sensitivities_tensor_adaptor_map.keys(): + # If it is found from input gradients, the tensor_adaptor will have those values, + # otherwise it will have representative zero tensor_adaptor. + control_physical_sensitivities_tensor_adaptor_map[physical_control_variable] = control_ta # map the physical control variable sensitivities to one control space - mapped_gradients.append(control.MapGradient(control_physical_sensitivities_container_expression_map)) + mapped_gradients.append(control.MapGradient(control_physical_sensitivities_tensor_adaptor_map)) result = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([mapped_gradient for mapped_gradient in mapped_gradients], perform_collect_data_recursively=False, perform_store_data_recursively=False) result.CollectData() From 5ff12ae513edb66d3a2a8428e317786f8420fa89 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 6 Feb 2026 08:36:53 +0100 Subject: [PATCH 058/116] remove expression tests --- .../tests/test_OptimizationApplication.py | 8 -------- .../tests/test_OptimizationApplication_mpi.py | 8 -------- 2 files changed, 16 deletions(-) diff --git a/applications/OptimizationApplication/tests/test_OptimizationApplication.py b/applications/OptimizationApplication/tests/test_OptimizationApplication.py index 68f1c4bd91d7..5e468ebd56da 100644 --- a/applications/OptimizationApplication/tests/test_OptimizationApplication.py +++ b/applications/OptimizationApplication/tests/test_OptimizationApplication.py @@ -32,9 +32,6 @@ import test_model_part_utils import test_model_part_controllers import test_connectivity_preserving_model_part_controller -import test_container_expression_utils -import test_container_expression -import test_collective_expressions import test_sigmoidal_projection import test_buffered_dict import control.test_master_control @@ -90,7 +87,6 @@ def AssembleTestSuites(): smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_model_part_utils.TestOptAppModelPartUtils])) smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_model_part_utils.TestModelPartUtilities])) smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_response_utilities.TestResponseUtilities])) - smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_container_expression_utils.TestContainerExpressionUtils])) smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([responses_tests.test_response_routine.TestResponseRoutine])) smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([responses_tests.test_standardized_responses.TestStandardizedObjective])) @@ -106,10 +102,6 @@ def AssembleTestSuites(): smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([responses_tests.test_discrete_value_residual_response_function.TestDiscreteValueResidualResponseFunctionLogarithm])) smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_external_response_function.TestExternalResponseFunction])) - smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_container_expression.TestConditionPropertiesExpression])) - smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_container_expression.TestElementPropertiesExpression])) - smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_collective_expressions.TestCollectiveExpressions])) - smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_sigmoidal_projection.TestSigmoidalProjection])) smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_model_part_controllers.TestMdpaModelPartController])) diff --git a/applications/OptimizationApplication/tests/test_OptimizationApplication_mpi.py b/applications/OptimizationApplication/tests/test_OptimizationApplication_mpi.py index cf56e1d34707..4b52c099053f 100644 --- a/applications/OptimizationApplication/tests/test_OptimizationApplication_mpi.py +++ b/applications/OptimizationApplication/tests/test_OptimizationApplication_mpi.py @@ -9,9 +9,6 @@ # Import the tests or test_classes to create the suits import test_model_part_utils -import test_container_expression_utils -import test_container_expression -import test_collective_expressions import process_tests.test_optimization_problem_ascii_output_process def AssembleTestSuites(): @@ -33,11 +30,6 @@ def AssembleTestSuites(): # adding custom process tests smallMPISuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_model_part_utils.TestOptAppModelPartUtils])) - smallMPISuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_container_expression_utils.TestContainerExpressionUtils])) - - smallMPISuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_container_expression.TestConditionPropertiesExpression])) - smallMPISuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_container_expression.TestElementPropertiesExpression])) - smallMPISuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_collective_expressions.TestCollectiveExpressions])) smallMPISuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([process_tests.test_optimization_problem_ascii_output_process.TestOptimizationProblemAsciiOutputProcess])) From 0fb9f75fba4b7c3aae960cf7a6cf436c8eba03da Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 6 Feb 2026 08:43:33 +0100 Subject: [PATCH 059/116] update kratos analysis execution policy --- .../kratos_analysis_execution_policy.py | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/applications/OptimizationApplication/python_scripts/execution_policies/kratos_analysis_execution_policy.py b/applications/OptimizationApplication/python_scripts/execution_policies/kratos_analysis_execution_policy.py index 2db1fd9ea66f..986225b9115c 100644 --- a/applications/OptimizationApplication/python_scripts/execution_policies/kratos_analysis_execution_policy.py +++ b/applications/OptimizationApplication/python_scripts/execution_policies/kratos_analysis_execution_policy.py @@ -95,39 +95,39 @@ def _OutputAnalysisData(self): unbuffered_data = ComponentDataView(self, self.optimization_problem).GetUnBufferedData() for model_part in self.model_parts: for variable in self.nodal_solution_step_data_variables: - nodal_field = Kratos.Expression.NodalExpression(model_part) - Kratos.Expression.VariableExpressionIO.Read(nodal_field, variable, True) - unbuffered_data.SetValue(variable.Name(), nodal_field.Clone(), overwrite=True) + nodal_field = Kratos.TensorAdaptors.HistoricalVariableTensorAdaptor(model_part.Nodes, variable) + nodal_field.CollectData() + unbuffered_data.SetValue(variable.Name(), nodal_field, overwrite=True) for variable in self.nodal_data_value_variables: - nodal_field = Kratos.Expression.NodalExpression(model_part) - Kratos.Expression.VariableExpressionIO.Read(nodal_field, variable, False) - unbuffered_data.SetValue(variable.Name(), nodal_field.Clone(), overwrite=True) + nodal_field = Kratos.TensorAdaptors.VariableTensorAdaptor(model_part.Nodes, variable) + nodal_field.CollectData() + unbuffered_data.SetValue(variable.Name(), nodal_field, overwrite=True) for variable in self.element_data_value_variables: - elem_field = Kratos.Expression.ElementExpression(model_part) - Kratos.Expression.VariableExpressionIO.Read(elem_field, variable) - unbuffered_data.SetValue(variable.Name(), elem_field.Clone(), overwrite=True) + elem_field = Kratos.TensorAdaptors.VariableTensorAdaptor(model_part.Elements, variable) + elem_field.CollectData() + unbuffered_data.SetValue(variable.Name(), elem_field, overwrite=True) for variable in self.element_properties_value_variables: - elem_field = Kratos.Expression.ElementExpression(model_part) - KratosOA.PropertiesVariableExpressionIO.Read(elem_field, variable) - unbuffered_data.SetValue(variable.Name(), elem_field.Clone(), overwrite=True) + elem_field = KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(model_part.Elements, variable) + elem_field.CollectData() + unbuffered_data.SetValue(variable.Name(), elem_field, overwrite=True) for variable in self.element_integration_point_value_variables: - elem_field = Kratos.Expression.ElementExpression(model_part) - Kratos.Expression.IntegrationPointExpressionIO.Read(elem_field, variable) - unbuffered_data.SetValue(variable.Name(), elem_field.Clone(), overwrite=True) + elem_field = Kratos.TensorAdaptors.GaussPointVariableTensorAdaptor(model_part.Elements, variable, model_part.ProcessInfo) + elem_field.CollectData() + unbuffered_data.SetValue(variable.Name(), elem_field, overwrite=True) for variable in self.condition_data_value_variables: - cond_field = Kratos.Expression.ConditionExpression(model_part) - Kratos.Expression.VariableExpressionIO.Read(cond_field, variable) - unbuffered_data.SetValue(variable.Name(), cond_field.Clone(), overwrite=True) + cond_field = Kratos.TensorAdaptors.VariableTensorAdaptor(model_part.Conditions, variable) + cond_field.CollectData() + unbuffered_data.SetValue(variable.Name(), cond_field, overwrite=True) for variable in self.condition_properties_value_variables: - cond_field = Kratos.Expression.ConditionExpression(model_part) - KratosOA.PropertiesVariableExpressionIO.Read(cond_field, variable) - unbuffered_data.SetValue(variable.Name(), cond_field.Clone(), overwrite=True) + cond_field = KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(model_part.Conditions, variable) + cond_field.CollectData() + unbuffered_data.SetValue(variable.Name(), cond_field, overwrite=True) for variable in self.condition_integration_point_value_variables: - cond_field = Kratos.Expression.ConditionExpression(model_part) - Kratos.Expression.IntegrationPointExpressionIO.Read(cond_field, variable) - unbuffered_data.SetValue(variable.Name(), cond_field.Clone(), overwrite=True) + cond_field = Kratos.TensorAdaptors.GaussPointVariableTensorAdaptor(model_part.Conditions, variable, model_part.ProcessInfo) + cond_field.CollectData() + unbuffered_data.SetValue(variable.Name(), cond_field, overwrite=True) @staticmethod def __GetVariablesList(variable_names_list: 'list[str]') -> 'list[Any]': From 7e856b0d9395f8894fe3936e0430950b5f9725af Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 6 Feb 2026 08:49:38 +0100 Subject: [PATCH 060/116] update optimization problem utilities --- .../utilities/optimization_problem_utilities.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/applications/OptimizationApplication/python_scripts/utilities/optimization_problem_utilities.py b/applications/OptimizationApplication/python_scripts/utilities/optimization_problem_utilities.py index 608b0f2c0d41..7a51acd89fd9 100644 --- a/applications/OptimizationApplication/python_scripts/utilities/optimization_problem_utilities.py +++ b/applications/OptimizationApplication/python_scripts/utilities/optimization_problem_utilities.py @@ -101,19 +101,21 @@ def OutputGradientFields(response: ResponseRoutine, optimization_problem: Optimi # save the physical gradients for post processing in unbuffered data container. for physical_var, physical_gradient in response.GetRequiredPhysicalGradients().items(): variable_name = f"d{response.GetResponseName()}_d{physical_var.Name()}" - for physical_gradient_expression in physical_gradient.GetContainerExpressions(): - unbuffered_data.SetValue(variable_name, physical_gradient_expression.Clone(), overwrite=True) + for physical_gradient_ta in physical_gradient.GetTensorAdaptors(): + unbuffered_data.SetValue(variable_name, Kratos.TensorAdaptors.DoubleTensorAdaptor(physical_gradient_ta), overwrite=True) # save the filtered gradients for post processing in unbuffered data container. - for gradient_container_expression, control in zip(response.GetMappedGradients().GetContainerExpressions(), response.GetMasterControl().GetListOfControls()): + for gradient_container_ta, control in zip(response.GetMappedGradients().GetTensorAdaptors(), response.GetMasterControl().GetListOfControls()): variable_name = f"d{response.GetResponseName()}_d{control.GetName()}" - unbuffered_data.SetValue(variable_name, gradient_container_expression.Clone(), overwrite=True) + unbuffered_data.SetValue(variable_name, Kratos.TensorAdaptors.DoubleTensorAdaptor(gradient_container_ta), overwrite=True) else: # save the physical gradients for post processing in unbuffered data container. for physical_var, physical_gradient in response.GetRequiredPhysicalGradients().items(): variable_name = f"d{response.GetResponseName()}_d{physical_var.Name()}" - for physical_gradient_expression in physical_gradient.GetContainerExpressions(): - unbuffered_data.SetValue(variable_name, physical_gradient_expression.Clone() * 0.0, overwrite=True) + for physical_gradient_ta in physical_gradient.GetTensorAdaptors(): + temp_ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(physical_gradient_ta) + temp_ta.data[:] = 0.0 + unbuffered_data.SetValue(variable_name, temp_ta, overwrite=True) # save the filtered gradients for post processing in unbuffered data container. for control in response.GetMasterControl().GetListOfControls(): From 9304412217d586f1d3abbba0678e05646fa51d9e Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 6 Feb 2026 09:03:43 +0100 Subject: [PATCH 061/116] update response routine --- .../responses/response_routine.py | 16 ++++---- .../responses_tests/test_response_routine.py | 38 +++++++++++-------- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/applications/OptimizationApplication/python_scripts/responses/response_routine.py b/applications/OptimizationApplication/python_scripts/responses/response_routine.py index 7dbab5981cba..e0bfc92ca36e 100644 --- a/applications/OptimizationApplication/python_scripts/responses/response_routine.py +++ b/applications/OptimizationApplication/python_scripts/responses/response_routine.py @@ -40,7 +40,7 @@ def Initialize(self): if required_physical_variable not in self.__response.GetImplementedPhysicalKratosVariables(): list_of_independent_variables.append(required_physical_variable) - # now remove this independent collective expression from the require collective expressions map. + # now remove this independent combined tensor adaptor from the require combined tensor adaptors map. for independent_variable in list_of_independent_variables: del self.__required_physical_gradients[independent_variable] @@ -86,12 +86,12 @@ def CalculateValue(self, control_field: Kratos.TensorAdaptors.DoubleCombinedTens if self.__response_value is None: self.my_current_control_field = Kratos.TensorAdaptors.DoubleTensorAdaptor(control_field) - if not math.isclose(numpy.linalg.norm(self.my_current_control_field.data, ord="inf"), 0.0, abs_tol=1e-16): - rel_diff = (self.my_current_control_field.data - control_field.data) / numpy.linalg.norm(self.my_current_control_field.data, ord="inf") + if not math.isclose(numpy.linalg.norm(self.my_current_control_field.data, ord=numpy.inf), 0.0, abs_tol=1e-16): + rel_diff = (self.my_current_control_field.data - control_field.data) / numpy.linalg.norm(self.my_current_control_field.data, ord=numpy.inf) else: rel_diff = (self.my_current_control_field.data - control_field.data) - norm = numpy.linalg.norm(rel_diff, ord="inf") + norm = numpy.linalg.norm(rel_diff, ord=numpy.inf) if not math.isclose(norm, 0.0, abs_tol=1e-16): compute_response_value_flag = True @@ -117,19 +117,19 @@ def CalculateValue(self, control_field: Kratos.TensorAdaptors.DoubleCombinedTens Kratos.Logger.PrintInfo(f"The control field is not updated, hence the response value is not computed for {self.GetResponseName()}.") # Update current control field state - self.my_current_control_field.data = control_field.data + self.my_current_control_field.data[:] = control_field.data return self.__response_value def CalculateGradient(self) -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: - """Returns Collective expression containing all the control space gradients for all control variable types (fields). + """Returns CombinedTensorAdaptor containing all the control space gradients for all control variable types (fields). Notes: 1. It expects that the CalculateValue is called. 2. The gradients are computed with respect to updates from master control. Returns: - Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: Returns mapped gradients collective expression. + Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: Returns mapped gradients combined tensor adaptor. """ # fills the proper physical gradients from the response self.__response.CalculateGradient(self.__required_physical_gradients) @@ -144,7 +144,7 @@ def GetMappedGradients(self): def GetRequiredPhysicalGradients(self) -> 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]': """Returns required physical gradients by this response - This method returns required physical gradients. The expressions may or not be empty field + This method returns required physical gradients. The tensor adaptors may or not be empty field depending on CalculateGradient is called or not. Returns: diff --git a/applications/OptimizationApplication/tests/responses_tests/test_response_routine.py b/applications/OptimizationApplication/tests/responses_tests/test_response_routine.py index 81a355c5cd00..f4ee3217392e 100644 --- a/applications/OptimizationApplication/tests/responses_tests/test_response_routine.py +++ b/applications/OptimizationApplication/tests/responses_tests/test_response_routine.py @@ -1,10 +1,10 @@ +import numpy import KratosMultiphysics as Kratos import KratosMultiphysics.OptimizationApplication as KratosOA import KratosMultiphysics.KratosUnittest as kratos_unittest from KratosMultiphysics.OptimizationApplication.controls.master_control import MasterControl from KratosMultiphysics.OptimizationApplication.controls.material.material_properties_control import MaterialPropertiesControl -from KratosMultiphysics.OptimizationApplication.utilities.helper_utilities import IsSameContainerExpression from KratosMultiphysics.OptimizationApplication.responses.mass_response_function import MassResponseFunction from KratosMultiphysics.OptimizationApplication.responses.response_routine import ResponseRoutine @@ -79,52 +79,60 @@ def setUpClass(cls): def test_CalculateValue(self): control_field = self.master_control.GetEmptyField() - KratosOA.CollectiveExpressionIO.Read(control_field, KratosOA.CollectiveExpressionIO.PropertiesVariable(Kratos.DENSITY)) + for ta in control_field.GetTensorAdaptors(): + KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(ta, Kratos.DENSITY, copy=False).CollectData() + Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(control_field, perform_collect_data_recursively=False, copy=False).CollectData() + value = self.response_routine.CalculateValue(control_field) self.assertEqual(value, 84) # now change the control field where response does not depend on # changing a variable such as YOUNG_MODULUS - Kratos.Expression.LiteralExpressionIO.SetData(control_field.GetContainerExpressions()[1], 2.0) + control_field.GetTensorAdaptors()[1].data[:] = 2.0 + Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(control_field, perform_collect_data_recursively=False, copy=False).CollectData() value = self.response_routine.CalculateValue(control_field) self.assertEqual(value, 84) # now change a dependent variable where the domain is not having intersection # changing DENSITY variable - Kratos.Expression.LiteralExpressionIO.SetData(control_field.GetContainerExpressions()[3], 3.0) + control_field.GetTensorAdaptors()[3].data[:] = 3.0 + Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(control_field, perform_collect_data_recursively=False, copy=False).CollectData() value = self.response_routine.CalculateValue(control_field) self.assertEqual(value, 84) # now change a dependent field - Kratos.Expression.LiteralExpressionIO.SetData(control_field.GetContainerExpressions()[0], 3.0) + control_field.GetTensorAdaptors()[0].data[:] = 3.0 + Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(control_field, perform_collect_data_recursively=False, copy=False).CollectData() value = self.response_routine.CalculateValue(control_field) self.assertEqual(value, 66) def test_CalculateGradient(self): control_field = self.master_control.GetEmptyField() - KratosOA.CollectiveExpressionIO.Read(control_field, KratosOA.CollectiveExpressionIO.PropertiesVariable(Kratos.DENSITY)) + for ta in control_field.GetTensorAdaptors(): + KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(ta, Kratos.DENSITY, copy=False).CollectData() + Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(control_field, perform_collect_data_recursively=False, copy=False).CollectData() # Calculate value should always be called once before the calculate gradient _ = self.response_routine.CalculateValue(control_field) gradient = self.response_routine.CalculateGradient() - self.assertEqual(len(gradient.GetContainerExpressions()), 4) + self.assertEqual(len(gradient.GetTensorAdaptors()), 4) # mass response has gradients w.r.t. control1. - control_1_gradient = gradient.GetContainerExpressions()[0] - self.assertEqual(Kratos.Expression.Utils.NormL2(control_1_gradient), 20.09975124224178) + control_1_gradient = gradient.GetTensorAdaptors()[0] + self.assertEqual(numpy.linalg.norm(control_1_gradient.data), 20.09975124224178) # mass response has gradients w.r.t. YOUNG_MODULUS even the response evaluated in the same control2 domain (same model part). - control_2_gradient = gradient.GetContainerExpressions()[1] - self.assertEqual(Kratos.Expression.Utils.NormInf(control_2_gradient), 0.0) + control_2_gradient = gradient.GetTensorAdaptors()[1] + self.assertEqual(numpy.linalg.norm(control_2_gradient.data, ord=numpy.inf), 0.0) # mass response has gradients w.r.t. control3. - control_3_gradient = gradient.GetContainerExpressions()[2] - self.assertEqual(Kratos.Expression.Utils.NormL2(control_3_gradient), 20.09975124224178) + control_3_gradient = gradient.GetTensorAdaptors()[2] + self.assertEqual(numpy.linalg.norm(control_3_gradient.data), 20.09975124224178) # mass response has gradients w.r.t. DENSITY because evaluation and control domains does not have an intersection. - control_4_gradient = gradient.GetContainerExpressions()[3] - self.assertEqual(Kratos.Expression.Utils.NormInf(control_4_gradient), 0.0) + control_4_gradient = gradient.GetTensorAdaptors()[3] + self.assertEqual(numpy.linalg.norm(control_4_gradient.data, ord=numpy.inf), 0.0) if __name__ == "__main__": kratos_unittest.main() \ No newline at end of file From 0bb8c11d36eaacf719ace24205381e3e3ff9d35a Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Sat, 7 Feb 2026 08:16:29 +0100 Subject: [PATCH 062/116] update line search to ta --- .../utilities/opt_line_search.py | 77 ++++++++-------- .../tests/algorithm_tests/test_line_search.py | 87 ++++++++++--------- 2 files changed, 86 insertions(+), 78 deletions(-) diff --git a/applications/OptimizationApplication/python_scripts/utilities/opt_line_search.py b/applications/OptimizationApplication/python_scripts/utilities/opt_line_search.py index 7b456ee580ad..1237cc137430 100644 --- a/applications/OptimizationApplication/python_scripts/utilities/opt_line_search.py +++ b/applications/OptimizationApplication/python_scripts/utilities/opt_line_search.py @@ -1,5 +1,4 @@ import KratosMultiphysics as Kratos -import KratosMultiphysics.OptimizationApplication as KratosOA from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import DictLogger @@ -41,19 +40,18 @@ def ComputeScaleFactor(self) -> float: if not algorithm_buffered_data.HasValue("search_direction"): raise RuntimeError(f"Algorithm data does not contain computed \"search_direction\".\nData:\n{algorithm_buffered_data}" ) + search_direction: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor = algorithm_buffered_data["search_direction"] if self._gradient_scaling == "inf_norm": - norm = KratosOA.ExpressionUtils.NormInf(algorithm_buffered_data["search_direction"]) + return numpy.linalg.norm(search_direction.data, ord=numpy.inf) elif self._gradient_scaling == "l2_norm": - norm = KratosOA.ExpressionUtils.NormL2(algorithm_buffered_data["search_direction"]) + return numpy.linalg.norm(search_direction.data) elif self._gradient_scaling == "none": - norm = 1.0 + return 1.0 else: raise RuntimeError("\"gradient_scaling\" has unknown type.") - return norm - @time_decorator() - def ComputeStep(self) -> float: + def ComputeStep(self) -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: norm = self.ComputeScaleFactor() if not math.isclose(norm, 0.0, abs_tol=1e-16): self.step = self._init_step / norm @@ -62,7 +60,10 @@ def ComputeStep(self) -> float: DictLogger("Line Search info",self.GetInfo()) - return self.step + algorithm_buffered_data = ComponentDataView("algorithm", self._optimization_problem).GetBufferedData() + step = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(algorithm_buffered_data["search_direction"]) + step.data[:] = self.step + return step def GetInfo(self) -> dict: info = {'type': 'constant', @@ -88,7 +89,7 @@ def __init__(self, parameters: Kratos.Parameters, optimization_problem: Optimiza self._gradient_scaling = parameters["gradient_scaling"].GetString() @time_decorator() - def ComputeStep(self) -> KratosOA.CollectiveExpression: + def ComputeStep(self) -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: algorithm_buffered_data = ComponentDataView("algorithm", self._optimization_problem).GetBufferedData() norm = self.ComputeScaleFactor() if math.isclose(norm, 0.0, abs_tol=1e-16): @@ -96,12 +97,12 @@ def ComputeStep(self) -> KratosOA.CollectiveExpression: if self._optimization_problem.GetStep() == 0: self.step = self._init_step / norm else: - current_search_direction = algorithm_buffered_data.GetValue("search_direction", 0) - previous_search_direction = algorithm_buffered_data.GetValue("search_direction", 1) - y = previous_search_direction - current_search_direction - d = algorithm_buffered_data.GetValue("control_field_update", 1) - dy = KratosOA.ExpressionUtils.InnerProduct(d,y) - dd = KratosOA.ExpressionUtils.InnerProduct(d,d) + current_search_direction: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor = algorithm_buffered_data.GetValue("search_direction", 0) + previous_search_direction: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor = algorithm_buffered_data.GetValue("search_direction", 1) + y = previous_search_direction.data - current_search_direction.data + d: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor = algorithm_buffered_data.GetValue("control_field_update", 1) + dy = numpy.inner(d.data[:].ravel(), y.ravel()) + dd = numpy.inner(d.data[:].ravel(), d.data[:].ravel()) if math.isclose(dy, 0.0, abs_tol=1e-16): self.step = self._max_step / norm else: @@ -112,7 +113,10 @@ def ComputeStep(self) -> KratosOA.CollectiveExpression: DictLogger("Line Search info",self.GetInfo()) - return self.step + algorithm_buffered_data = ComponentDataView("algorithm", self._optimization_problem).GetBufferedData() + step = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(algorithm_buffered_data["search_direction"]) + step.data[:] = self.step + return step def GetInfo(self) -> dict: info = {'type': 'BB_step', @@ -124,43 +128,40 @@ def GetInfo(self) -> dict: class QNBBStep(BBStep): @time_decorator() - def ComputeStep(self) -> KratosOA.CollectiveExpression: + def ComputeStep(self) -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: algorithm_buffered_data = ComponentDataView("algorithm", self._optimization_problem).GetBufferedData() norm = self.ComputeScaleFactor() if math.isclose(norm, 0.0, abs_tol=1e-16): norm = 1.0 - self.step = algorithm_buffered_data.GetValue("search_direction", 0).Clone() - self.step *= 0.0 + self.step = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(algorithm_buffered_data.GetValue("search_direction", 0), perform_store_data_recursively=False) + self.step.data[:] = 0.0 if not algorithm_buffered_data.HasValue("step_size"): algorithm_buffered_data["step_size"] = self.step - self.step_numpy = self.step.Evaluate() + if self._optimization_problem.GetStep() == 0: - self.step_numpy[:] = self._init_step / norm + self.step.data[:] = self._init_step / norm else: - current_search_direction = algorithm_buffered_data.GetValue("search_direction", 0) - previous_search_direction = algorithm_buffered_data.GetValue("search_direction", 1) - y = previous_search_direction - current_search_direction - y = y.Evaluate() - d = algorithm_buffered_data.GetValue("control_field_update", 1) - d = d.Evaluate() + current_search_direction: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor = algorithm_buffered_data.GetValue("search_direction", 0) + previous_search_direction: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor = algorithm_buffered_data.GetValue("search_direction", 1) + y = previous_search_direction.data - current_search_direction.data + d: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor = algorithm_buffered_data.GetValue("control_field_update", 1) + d = d.data[:] for i in range(len(y)): dy = numpy.dot(d[i], y[i]) dd = numpy.dot(d[i], d[i]) - + if math.isclose(dy, 0.0, abs_tol=1e-16): - self.step_numpy[i] = self._max_step / norm + self.step.data[i] = self._max_step / norm else: - self.step_numpy[i] = abs( dd / dy ) + self.step.data[i] = abs( dd / dy ) - if isinstance(d[i], (float, int, numpy.float64)) and self.step_numpy[i] > self._max_step / norm: - self.step_numpy[i] = self._max_step / norm - elif isinstance(d[i], (numpy.ndarray)) and self.step_numpy[i][0] > self._max_step / norm: - self.step_numpy[i] = self._max_step / norm - - DictLogger("Line Search info",self.GetInfo()) + if isinstance(d[i], (float, int, numpy.float64)) and self.step.data[i] > self._max_step / norm: + self.step.data[i] = self._max_step / norm + elif isinstance(d[i], (numpy.ndarray)) and self.step.data[i][0] > self._max_step / norm: + self.step.data[i] = self._max_step / norm - shape = [c.GetItemShape() for c in self.step.GetContainerExpressions()] - KratosOA.CollectiveExpressionIO.Read(self.step, self.step_numpy, shape) + DictLogger("Line Search info",self.GetInfo()) + self.step.StoreData() return self.step def GetInfo(self) -> dict: diff --git a/applications/OptimizationApplication/tests/algorithm_tests/test_line_search.py b/applications/OptimizationApplication/tests/algorithm_tests/test_line_search.py index 23074219c5a9..7828050caa95 100644 --- a/applications/OptimizationApplication/tests/algorithm_tests/test_line_search.py +++ b/applications/OptimizationApplication/tests/algorithm_tests/test_line_search.py @@ -17,13 +17,20 @@ def setUpClass(cls): ComponentDataView("algorithm", cls.optimization_problem).SetDataBuffer(2) ComponentDataView("algorithm", cls.optimization_problem_one_step).SetDataBuffer(2) - sensitivity = KratosOA.CollectiveExpression([Kratos.Expression.ElementExpression(cls.model_part)]) - KratosOA.CollectiveExpressionIO.Read(sensitivity, KratosOA.CollectiveExpressionIO.PropertiesVariable(Kratos.DENSITY)) - ComponentDataView("algorithm", cls.optimization_problem).GetBufferedData()["search_direction"] = sensitivity * 5 + sensitivity = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(cls.model_part.Elements, Kratos.DENSITY)]) + sensitivity.CollectData() + + search_direction = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(sensitivity) + search_direction.data[:] *= 5.0 + control_field_update = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(sensitivity) + control_field_update.data[:] *= 6.0 + + ComponentDataView("algorithm", cls.optimization_problem).GetBufferedData()["search_direction"] = search_direction ComponentDataView("algorithm", cls.optimization_problem_one_step).GetBufferedData()["search_direction"] = sensitivity - ComponentDataView("algorithm", cls.optimization_problem).GetBufferedData()["control_field_update"] = sensitivity * 6 + ComponentDataView("algorithm", cls.optimization_problem).GetBufferedData()["control_field_update"] = control_field_update + cls.optimization_problem.AdvanceStep() - ComponentDataView("algorithm", cls.optimization_problem).GetBufferedData()["search_direction"] = sensitivity + ComponentDataView("algorithm", cls.optimization_problem).GetBufferedData()["search_direction"] = sensitivity @classmethod def CreateElements(cls): cls.model_part.CreateNewNode(1, 0.0, 0.0, 0.0) @@ -49,7 +56,7 @@ def test_ConstantLineSearchInfNorm(self): }""") line_search = CreateLineSearch(line_search_settings, self.optimization_problem) alpha = line_search.ComputeStep() - self.assertEqual(alpha, 0.75) + self.assertAlmostEqual(numpy.linalg.norm(alpha.data[:] - 0.75), 0.0) def test_ConstantLineSearchL2Norm(self): line_search_settings = Kratos.Parameters("""{ @@ -59,7 +66,7 @@ def test_ConstantLineSearchL2Norm(self): }""") line_search = CreateLineSearch(line_search_settings, self.optimization_problem) alpha = line_search.ComputeStep() - self.assertEqual(alpha, 0.6708203932499369) + self.assertAlmostEqual(numpy.linalg.norm(alpha.data[:] - 0.6708203932499369), 0.0) def test_ConstantLineSearchNoneNorm(self): line_search_settings = Kratos.Parameters("""{ @@ -69,7 +76,7 @@ def test_ConstantLineSearchNoneNorm(self): }""") line_search = CreateLineSearch(line_search_settings, self.optimization_problem) alpha = line_search.ComputeStep() - self.assertEqual(alpha, 3.0) + self.assertAlmostEqual(numpy.linalg.norm(alpha.data[:] - 3.0), 0.0) def test_BBStepDefParam(self): line_search_settings = Kratos.Parameters("""{ @@ -80,7 +87,7 @@ def test_BBStepDefParam(self): }""") line_search = CreateLineSearch(line_search_settings, self.optimization_problem) alpha = line_search.ComputeStep() - self.assertEqual(alpha, 0.0) + self.assertEqual(numpy.linalg.norm(alpha.data[:]), 0.0) def test_BBStepInfNorm(self): line_search_settings = Kratos.Parameters("""{ @@ -91,7 +98,7 @@ def test_BBStepInfNorm(self): }""") line_search = CreateLineSearch(line_search_settings, self.optimization_problem) alpha = line_search.ComputeStep() - self.assertEqual(alpha, 1.5) + self.assertEqual(numpy.linalg.norm(alpha.data[:] - 1.5), 0.0) def test_BBStepInfNormMax(self): line_search_settings = Kratos.Parameters("""{ @@ -102,7 +109,7 @@ def test_BBStepInfNormMax(self): }""") line_search = CreateLineSearch(line_search_settings, self.optimization_problem) alpha = line_search.ComputeStep() - self.assertEqual(alpha, 0.125) + self.assertEqual(numpy.linalg.norm(alpha.data[:] - 0.125), 0.0) def test_BBStepL2Norm(self): line_search_settings = Kratos.Parameters("""{ @@ -113,7 +120,7 @@ def test_BBStepL2Norm(self): }""") line_search = CreateLineSearch(line_search_settings, self.optimization_problem) alpha = line_search.ComputeStep() - self.assertEqual(alpha, 1.5) + self.assertEqual(numpy.linalg.norm(alpha.data[:] - 1.5), 0.0) def test_BBStepL2NormMax(self): line_search_settings = Kratos.Parameters("""{ @@ -124,7 +131,7 @@ def test_BBStepL2NormMax(self): }""") line_search = CreateLineSearch(line_search_settings, self.optimization_problem) alpha = line_search.ComputeStep() - self.assertEqual(alpha, 0.22360679774997896) + self.assertEqual(numpy.linalg.norm(alpha.data[:] -0.22360679774997896), 0.0) def test_BBStepNoneNorm(self): line_search_settings = Kratos.Parameters("""{ @@ -135,7 +142,7 @@ def test_BBStepNoneNorm(self): }""") line_search = CreateLineSearch(line_search_settings, self.optimization_problem) alpha = line_search.ComputeStep() - self.assertEqual(alpha, 1.5) + self.assertEqual(numpy.linalg.norm(alpha.data[:] - 1.5), 0.0) def test_BBStepNoneNormMaxStep(self): line_search_settings = Kratos.Parameters("""{ @@ -146,7 +153,7 @@ def test_BBStepNoneNormMaxStep(self): }""") line_search = CreateLineSearch(line_search_settings, self.optimization_problem) alpha = line_search.ComputeStep() - self.assertEqual(alpha, 1.0) + self.assertEqual(numpy.linalg.norm(alpha.data[:] - 1.0), 0.0) def test_BBStepNoneNormInitStep(self): line_search_settings = Kratos.Parameters("""{ @@ -157,7 +164,7 @@ def test_BBStepNoneNormInitStep(self): }""") line_search = CreateLineSearch(line_search_settings, self.optimization_problem_one_step) alpha = line_search.ComputeStep() - self.assertEqual(alpha, 3.0) + self.assertEqual(numpy.linalg.norm(alpha.data[:] - 3.0), 0.0) def test_QNBBStepDefParam(self): line_search_settings = Kratos.Parameters("""{ @@ -167,9 +174,9 @@ def test_QNBBStepDefParam(self): "max_step" : 0.0 }""") line_search = CreateLineSearch(line_search_settings, self.optimization_problem) - alpha = line_search.ComputeStep().Evaluate() - self.assertEqual(alpha[0], 0.0) - self.assertEqual(alpha[1], 0.0) + alpha = line_search.ComputeStep() + self.assertEqual(alpha.data[0], 0.0) + self.assertEqual(alpha.data[1], 0.0) def test_QNBBStepInfNorm(self): line_search_settings = Kratos.Parameters("""{ @@ -179,9 +186,9 @@ def test_QNBBStepInfNorm(self): "max_step" : 10.0 }""") line_search = CreateLineSearch(line_search_settings, self.optimization_problem) - alpha = line_search.ComputeStep().Evaluate() - self.assertEqual(alpha[0], 1.5) - self.assertEqual(alpha[1], 1.5) + alpha = line_search.ComputeStep() + self.assertEqual(alpha.data[0], 1.5) + self.assertEqual(alpha.data[1], 1.5) def test_QNBBStepInfNormMax(self): line_search_settings = Kratos.Parameters("""{ @@ -191,9 +198,9 @@ def test_QNBBStepInfNormMax(self): "max_step" : 1.0 }""") line_search = CreateLineSearch(line_search_settings, self.optimization_problem) - alpha = line_search.ComputeStep().Evaluate() - self.assertEqual(alpha[0], 0.25) - self.assertEqual(alpha[1], 0.25) + alpha = line_search.ComputeStep() + self.assertEqual(alpha.data[0], 0.25) + self.assertEqual(alpha.data[1], 0.25) def test_QNBBStepL2Norm(self): line_search_settings = Kratos.Parameters("""{ @@ -203,9 +210,9 @@ def test_QNBBStepL2Norm(self): "max_step" : 10.0 }""") line_search = CreateLineSearch(line_search_settings, self.optimization_problem) - alpha = line_search.ComputeStep().Evaluate() - self.assertEqual(alpha[0], 1.5) - self.assertEqual(alpha[1], 1.5) + alpha = line_search.ComputeStep() + self.assertEqual(alpha.data[0], 1.5) + self.assertEqual(alpha.data[1], 1.5) def test_QNBBStepL2NormMax(self): line_search_settings = Kratos.Parameters("""{ @@ -215,9 +222,9 @@ def test_QNBBStepL2NormMax(self): "max_step" : 1.0 }""") line_search = CreateLineSearch(line_search_settings, self.optimization_problem) - alpha = line_search.ComputeStep().Evaluate() - self.assertEqual(alpha[0], 0.22360679774997896) - self.assertEqual(alpha[1], 0.22360679774997896) + alpha = line_search.ComputeStep() + self.assertEqual(alpha.data[0], 0.22360679774997896) + self.assertEqual(alpha.data[1], 0.22360679774997896) def test_QNBBStepNoneNorm(self): line_search_settings = Kratos.Parameters("""{ @@ -227,9 +234,9 @@ def test_QNBBStepNoneNorm(self): "max_step" : 10.0 }""") line_search = CreateLineSearch(line_search_settings, self.optimization_problem) - alpha = line_search.ComputeStep().Evaluate() - self.assertEqual(alpha[0], 1.5) - self.assertEqual(alpha[1], 1.5) + alpha = line_search.ComputeStep() + self.assertEqual(alpha.data[0], 1.5) + self.assertEqual(alpha.data[1], 1.5) def test_QNBBStepNoneNormMax(self): line_search_settings = Kratos.Parameters("""{ @@ -239,9 +246,9 @@ def test_QNBBStepNoneNormMax(self): "max_step" : 1.0 }""") line_search = CreateLineSearch(line_search_settings, self.optimization_problem) - alpha = line_search.ComputeStep().Evaluate() - self.assertEqual(alpha[0], 1.0) - self.assertEqual(alpha[1], 1.0) + alpha = line_search.ComputeStep() + self.assertEqual(alpha.data[0], 1.0) + self.assertEqual(alpha.data[1], 1.0) def test_QNBBStepNoneNormInitStep(self): line_search_settings = Kratos.Parameters("""{ @@ -251,9 +258,9 @@ def test_QNBBStepNoneNormInitStep(self): "max_step" : 10.0 }""") line_search = CreateLineSearch(line_search_settings, self.optimization_problem_one_step) - alpha = line_search.ComputeStep().Evaluate() - self.assertEqual(alpha[0], 3.0) - self.assertEqual(alpha[1], 3.0) + alpha = line_search.ComputeStep() + self.assertEqual(alpha.data[0], 3.0) + self.assertEqual(alpha.data[1], 3.0) if __name__ == "__main__": kratos_unittest.main() \ No newline at end of file From 288f21bae67d68f2a306f596480c17c6fa21c0c4 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Mon, 9 Feb 2026 10:25:52 +0100 Subject: [PATCH 063/116] minor --- .../python_scripts/utilities/opt_line_search.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/OptimizationApplication/python_scripts/utilities/opt_line_search.py b/applications/OptimizationApplication/python_scripts/utilities/opt_line_search.py index 1237cc137430..b02371ba76cb 100644 --- a/applications/OptimizationApplication/python_scripts/utilities/opt_line_search.py +++ b/applications/OptimizationApplication/python_scripts/utilities/opt_line_search.py @@ -42,7 +42,7 @@ def ComputeScaleFactor(self) -> float: search_direction: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor = algorithm_buffered_data["search_direction"] if self._gradient_scaling == "inf_norm": - return numpy.linalg.norm(search_direction.data, ord=numpy.inf) + return numpy.max(numpy.abs(search_direction.data)) elif self._gradient_scaling == "l2_norm": return numpy.linalg.norm(search_direction.data) elif self._gradient_scaling == "none": From 9a20fd0410b6706f04d2e62e68fda0304dea8b35 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Mon, 9 Feb 2026 10:30:27 +0100 Subject: [PATCH 064/116] update std. obj --- .../algorithms/standardized_objective.py | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/applications/OptimizationApplication/python_scripts/algorithms/standardized_objective.py b/applications/OptimizationApplication/python_scripts/algorithms/standardized_objective.py index 7913ba2f4568..0021007b220f 100644 --- a/applications/OptimizationApplication/python_scripts/algorithms/standardized_objective.py +++ b/applications/OptimizationApplication/python_scripts/algorithms/standardized_objective.py @@ -1,5 +1,4 @@ import KratosMultiphysics as Kratos -import KratosMultiphysics.OptimizationApplication as KratosOA from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem from KratosMultiphysics.OptimizationApplication.responses.response_routine import ResponseRoutine from KratosMultiphysics.OptimizationApplication.controls.master_control import MasterControl @@ -64,7 +63,7 @@ def GetInitialValue(self) -> float: else: raise RuntimeError(f"Response value for {self.GetResponseName()} is not calculated yet.") - def CalculateStandardizedValue(self, control_field: KratosOA.CollectiveExpression, save_value: bool = True) -> float: + def CalculateStandardizedValue(self, control_field: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor, save_value: bool = True) -> float: with TimeLogger(f"StandardizedObjective::Calculate {self.GetResponseName()} value", None, "Finished"): response_value = self.CalculateValue(control_field) standardized_response_value = response_value * self.__scaling @@ -86,29 +85,28 @@ def GetValue(self, step_index: int = 0) -> float: def GetStandardizedValue(self, step_index: int = 0) -> float: return self.GetValue(step_index) * self.__scaling - def CalculateStandardizedGradient(self, save_field: bool = True) -> KratosOA.CollectiveExpression: + def CalculateStandardizedGradient(self, save_field: bool = True) -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: with TimeLogger(f"StandardizedObjective::Calculate {self.GetResponseName()} gradients", None, "Finished"): - gradient_collective_expression = self.CalculateGradient() + gradient_cta = self.CalculateGradient() if save_field: # save the physical gradients for post processing in unbuffered data container. for physical_var, physical_gradient in self.GetRequiredPhysicalGradients().items(): - for physical_gradient_expression in physical_gradient.GetContainerExpressions(): - variable_name = f"d{self.GetResponseName()}_d{physical_var.Name()}_{physical_gradient_expression.GetModelPart().Name}" - if self.__unbuffered_data.HasValue(variable_name): del self.__unbuffered_data[variable_name] - # cloning is a cheap operation, it only moves underlying pointers - # does not create additional memory. - self.__unbuffered_data[variable_name] = physical_gradient_expression.Clone() + variable_name = f"d{self.GetResponseName()}_d{physical_var.Name()}" + if self.__unbuffered_data.HasValue(variable_name): del self.__unbuffered_data[variable_name] + self.__unbuffered_data[variable_name] = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(physical_gradient) # save the filtered gradients for post processing in unbuffered data container. - for gradient_container_expression, control in zip(gradient_collective_expression.GetContainerExpressions(), self.GetMasterControl().GetListOfControls()): - variable_name = f"d{self.GetResponseName()}_d{control.GetName()}_{physical_gradient_expression.GetModelPart().Name}" + for gradient_ta, control in zip(gradient_cta.GetTensorAdaptors(), self.GetMasterControl().GetListOfControls()): + variable_name = f"d{self.GetResponseName()}_d{control.GetName()}" if self.__unbuffered_data.HasValue(variable_name): del self.__unbuffered_data[variable_name] # cloning is a cheap operation, it only moves underlying pointers # does not create additional memory. - self.__unbuffered_data[variable_name] = gradient_container_expression.Clone() + self.__unbuffered_data[variable_name] = Kratos.TensorAdaptors.DoubleTensorAdaptor(gradient_ta) - return gradient_collective_expression * self.__scaling + gradient_cta.data[:] *= self.__scaling + Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(gradient_cta, perform_store_data_recursively=False, copy=False).StoreData() + return gradient_cta def GetRelativeChange(self) -> float: if self.__optimization_problem.GetStep() > 0: From 7c9d7a9a1af3c0a98fea8f724fe50e9f15ddf014 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Mon, 9 Feb 2026 10:32:25 +0100 Subject: [PATCH 065/116] update steepest descent --- .../algorithms/algorithm_steepest_descent.py | 40 ++++++++++--------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/applications/OptimizationApplication/python_scripts/algorithms/algorithm_steepest_descent.py b/applications/OptimizationApplication/python_scripts/algorithms/algorithm_steepest_descent.py index dbf12cf487b9..2fe64f5a5c8c 100644 --- a/applications/OptimizationApplication/python_scripts/algorithms/algorithm_steepest_descent.py +++ b/applications/OptimizationApplication/python_scripts/algorithms/algorithm_steepest_descent.py @@ -1,5 +1,4 @@ import KratosMultiphysics as Kratos -import KratosMultiphysics.OptimizationApplication as KratosOA from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem from KratosMultiphysics.OptimizationApplication.algorithms.standardized_objective import StandardizedObjective from KratosMultiphysics.OptimizationApplication.controls.master_control import MasterControl @@ -71,12 +70,12 @@ def __init__(self, model:Kratos.Model, parameters: Kratos.Parameters, optimizati def GetMinimumBufferSize(self) -> int: return 2 - def Check(self): + def Check(self) -> None: self.master_control.Check() self.__objective.Check() @time_decorator() - def Initialize(self): + def Initialize(self) -> None: self.converged = False self.__obj_val = None self.master_control.Initialize() @@ -85,31 +84,36 @@ def Initialize(self): self.algorithm_data = ComponentDataView("algorithm", self._optimization_problem) self._convergence_criteria.Initialize() - def Finalize(self): + def Finalize(self) -> None: self.master_control.Finalize() self.__objective.Finalize() self._convergence_criteria.Finalize() @time_decorator() - def ComputeSearchDirection(self, obj_grad) -> KratosOA.CollectiveExpression: - search_direction = obj_grad * -1.0 - self.algorithm_data.GetBufferedData()["search_direction"] = search_direction.Clone() + def ComputeSearchDirection(self, obj_grad: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor) -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: + search_direction = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(obj_grad) + search_direction.data[:] = obj_grad.data[:] * -1.0 + Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(search_direction, perform_store_data_recursively=False, copy=False).StoreData() + self.algorithm_data.GetBufferedData()["search_direction"] = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(search_direction) return search_direction @time_decorator() - def ComputeControlUpdate(self, alpha): - search_direction = self.algorithm_data.GetBufferedData()["search_direction"] - update = KratosOA.ExpressionUtils.Scale(search_direction, alpha) - self.algorithm_data.GetBufferedData()["control_field_update"] = update.Clone() + def ComputeControlUpdate(self, alpha: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor) -> None: + search_direction: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor = self.algorithm_data.GetBufferedData()["search_direction"] + update = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(search_direction) + update.data[:] *= alpha.data[:] + Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(update, perform_store_data_recursively=False, copy=False).StoreData() + self.algorithm_data.GetBufferedData()["control_field_update"] = update @time_decorator() - def UpdateControl(self) -> KratosOA.CollectiveExpression: - update = self.algorithm_data.GetBufferedData()["control_field_update"] - self.__control_field = KratosOA.ExpressionUtils.Collapse(self.__control_field + update) + def UpdateControl(self) -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: + update: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor = self.algorithm_data.GetBufferedData()["control_field_update"] + self.__control_field.data[:] += update.data + Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(self.__control_field, perform_store_data_recursively=False, copy=False).StoreData() @time_decorator() - def Output(self) -> KratosOA.CollectiveExpression: - self.algorithm_data.GetBufferedData()["control_field"] = self.__control_field.Clone() + def Output(self) -> None: + self.algorithm_data.GetBufferedData()["control_field"] = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(self.__control_field) for process in self._optimization_problem.GetListOfProcesses("output_processes"): if process.IsOutputStep(): process.PrintOutput() @@ -117,11 +121,11 @@ def Output(self) -> KratosOA.CollectiveExpression: def GetCurrentObjValue(self) -> float: return self.__obj_val - def GetCurrentControlField(self): + def GetCurrentControlField(self) -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: return self.__control_field @time_decorator() - def Solve(self): + def Solve(self) -> bool: while not self.converged: with OptimizationAlgorithmTimeLogger("AlgorithmSteepestDescent",self._optimization_problem.GetStep()): self._InitializeIteration() From 98c1ce95cc3831eb9baffdf849e089b3e7c19b84 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Mon, 9 Feb 2026 10:56:23 +0100 Subject: [PATCH 066/116] update std constraint --- .../algorithms/standardized_constraint.py | 28 +++++++++---------- .../test_standardized_responses.py | 7 +++-- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/applications/OptimizationApplication/python_scripts/algorithms/standardized_constraint.py b/applications/OptimizationApplication/python_scripts/algorithms/standardized_constraint.py index 6b9ee6ac3452..c95803eddf82 100644 --- a/applications/OptimizationApplication/python_scripts/algorithms/standardized_constraint.py +++ b/applications/OptimizationApplication/python_scripts/algorithms/standardized_constraint.py @@ -1,5 +1,4 @@ import KratosMultiphysics as Kratos -import KratosMultiphysics.OptimizationApplication as KratosOA from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem from KratosMultiphysics.OptimizationApplication.responses.response_routine import ResponseRoutine from KratosMultiphysics.OptimizationApplication.controls.master_control import MasterControl @@ -92,7 +91,7 @@ def GetStandardizedReferenceValue(self) -> float: else: raise RuntimeError(f"Response value for {self.GetResponseName()} is not calculated yet.") - def CalculateStandardizedValue(self, control_field: KratosOA.CollectiveExpression, save_value: bool = True) -> float: + def CalculateStandardizedValue(self, control_field: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor, save_value: bool = True) -> float: with TimeLogger(f"StandardizedConstraint::Calculate {self.GetResponseName()} value", None, "Finished"): response_value = self.CalculateValue(control_field) standardized_response_value = response_value * self.__scaling @@ -115,29 +114,30 @@ def CalculateStandardizedValue(self, control_field: KratosOA.CollectiveExpressio def IsActive(self): return self.GetStandardizedValue() > 0.0 - def CalculateStandardizedGradient(self, save_field: bool = True) -> KratosOA.CollectiveExpression: + def CalculateStandardizedGradient(self, save_field: bool = True) -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: with TimeLogger(f"StandardizedConstraint::Calculate {self.GetResponseName()} gradients", None, "Finished"): - gradient_collective_expression = self.CalculateGradient() + gradient_cta = self.CalculateGradient() if save_field: # save the physical gradients for post processing in unbuffered data container. for physical_var, physical_gradient in self.GetRequiredPhysicalGradients().items(): - for physical_gradient_expression in physical_gradient.GetContainerExpressions(): - variable_name = f"d{self.GetResponseName()}_d{physical_var.Name()}_{physical_gradient_expression.GetModelPart().Name}" - if self.__unbuffered_data.HasValue(variable_name): del self.__unbuffered_data[variable_name] - # cloning is a cheap operation, it only moves underlying pointers - # does not create additional memory. - self.__unbuffered_data[variable_name] = physical_gradient_expression.Clone() + variable_name = f"d{self.GetResponseName()}_d{physical_var.Name()}" + if self.__unbuffered_data.HasValue(variable_name): del self.__unbuffered_data[variable_name] + # cloning is a cheap operation, it only moves underlying pointers + # does not create additional memory. + self.__unbuffered_data[variable_name] = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(physical_gradient) # save the filtered gradients for post processing in unbuffered data container. - for gradient_container_expression, control in zip(gradient_collective_expression.GetContainerExpressions(), self.GetMasterControl().GetListOfControls()): - variable_name = f"d{self.GetResponseName()}_d{control.GetName()}_{physical_gradient_expression.GetModelPart().Name}" + for gradient_ta, control in zip(gradient_cta.GetTensorAdaptors(), self.GetMasterControl().GetListOfControls()): + variable_name = f"d{self.GetResponseName()}_d{control.GetName()}" if self.__unbuffered_data.HasValue(variable_name): del self.__unbuffered_data[variable_name] # cloning is a cheap operation, it only moves underlying pointers # does not create additional memory. - self.__unbuffered_data[variable_name] = gradient_container_expression.Clone() + self.__unbuffered_data[variable_name] = Kratos.TensorAdaptors.DoubleTensorAdaptor(gradient_ta) - return gradient_collective_expression * self.__scaling + gradient_cta.data[:] *= self.__scaling + Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(gradient_cta, perform_store_data_recursively=False, copy=False).StoreData() + return gradient_cta def GetValue(self, step_index: int = 0) -> float: return self.__buffered_data.GetValue("value", step_index) diff --git a/applications/OptimizationApplication/tests/responses_tests/test_standardized_responses.py b/applications/OptimizationApplication/tests/responses_tests/test_standardized_responses.py index 5790a9ef0ef3..23ad5ff46461 100644 --- a/applications/OptimizationApplication/tests/responses_tests/test_standardized_responses.py +++ b/applications/OptimizationApplication/tests/responses_tests/test_standardized_responses.py @@ -51,13 +51,16 @@ def setUpClass(cls): cls.properties_control.Initialize() cls.initial_configuration = cls.master_control.GetEmptyField() - KratosOA.CollectiveExpressionIO.Read(cls.initial_configuration, KratosOA.CollectiveExpressionIO.PropertiesVariable(Kratos.DENSITY)) + for ta in cls.initial_configuration.GetTensorAdaptors(): + KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(ta, Kratos.DENSITY, copy=False).StoreData() + Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(cls.initial_configuration, perform_store_data_recursively=False, copy=False).StoreData() def _CheckSensitivity(self, standardized_component: Union[StandardizedObjective, StandardizedConstraint], delta: float, precision: int): self.optimization_problem.AdvanceStep() ref_value = standardized_component.CalculateStandardizedValue(self.initial_configuration) gradients = standardized_component.CalculateStandardizedGradient() - KratosOA.CollectiveExpressionIO.Write(gradients, KratosOA.CollectiveExpressionIO.PropertiesVariable(Kratos.YOUNG_MODULUS)) + for ta in gradients.GetTensorAdaptors(): + KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(ta, Kratos.YOUNG_MODULUS, copy=False).StoreData() for element in self.model_part.Elements: element.Properties[Kratos.DENSITY] += delta current_configuration = self.master_control.GetControlField() From 022462a9baa960c65fe7aab20b17bfe0d2aac970 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Mon, 9 Feb 2026 13:36:47 +0100 Subject: [PATCH 067/116] update algo grad projection --- .../algorithm_gradient_projection.py | 80 +++++++++++++------ .../summary_orig.csv | 20 ++--- 2 files changed, 67 insertions(+), 33 deletions(-) diff --git a/applications/OptimizationApplication/python_scripts/algorithms/algorithm_gradient_projection.py b/applications/OptimizationApplication/python_scripts/algorithms/algorithm_gradient_projection.py index 5ce3662b32fe..f3825959af97 100644 --- a/applications/OptimizationApplication/python_scripts/algorithms/algorithm_gradient_projection.py +++ b/applications/OptimizationApplication/python_scripts/algorithms/algorithm_gradient_projection.py @@ -1,5 +1,5 @@ +import numpy import KratosMultiphysics as Kratos -import KratosMultiphysics.OptimizationApplication as KratosOA from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem from KratosMultiphysics.OptimizationApplication.algorithms.standardized_objective import StandardizedObjective from KratosMultiphysics.OptimizationApplication.controls.master_control import MasterControl @@ -11,8 +11,6 @@ from KratosMultiphysics.OptimizationApplication.utilities.helper_utilities import CallOnAll from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import time_decorator from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import OptimizationAlgorithmTimeLogger -from KratosMultiphysics.OptimizationApplication.utilities.list_collective_expression_utilities import CollectiveListCollectiveProduct -from KratosMultiphysics.OptimizationApplication.utilities.list_collective_expression_utilities import CollectiveListVectorProduct from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem_utilities import OutputGradientFields from KratosMultiphysics.OptimizationApplication.convergence_criteria.convergence_criterion import ConvergenceCriterion from KratosMultiphysics.OptimizationApplication.convergence_criteria.constraint_conv_criterion import ConstraintConvCriterion @@ -119,12 +117,18 @@ def Finalize(self): self._convergence_criteria.Finalize() @time_decorator() - def ComputeSearchDirection(self, obj_grad: KratosOA.CollectiveExpression, constr_grad: 'list[KratosOA.CollectiveExpression]') -> KratosOA.CollectiveExpression: + def ComputeSearchDirection(self, obj_grad: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor, constr_grad: 'list[Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]') -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: active_constraints_list = [self._constraints_list[i] for i in range(len(self._constraints_list)) if self.__constr_value[i] >= 0.0] number_of_active_constraints = len(active_constraints_list) + + search_direction = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(obj_grad, perform_collect_data_recursively=False, perform_store_data_recursively=False) + correction = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(obj_grad, perform_collect_data_recursively=False, perform_store_data_recursively=False) + if not number_of_active_constraints: - search_direction = obj_grad * -1.0 - correction = obj_grad * 0.0 + search_direction.data[:] *= -1.0 + search_direction.StoreData() + correction.data[:] = 0.0 + correction.StoreData() else: constraint_violations = Kratos.Vector(number_of_active_constraints) for i, active_constraint in enumerate(active_constraints_list): @@ -134,7 +138,7 @@ def ComputeSearchDirection(self, obj_grad: KratosOA.CollectiveExpression, constr ntn = Kratos.Matrix(number_of_active_constraints, number_of_active_constraints) for i in range(number_of_active_constraints): for j in range(i, number_of_active_constraints): - ntn[i, j] = KratosOA.ExpressionUtils.InnerProduct(constr_grad[i], constr_grad[j]) + ntn[i, j] = numpy.dot(constr_grad[i].data.ravel(), constr_grad[j].data.ravel()) ntn[j, i] = ntn[i, j] # get the inverse of ntn @@ -148,25 +152,32 @@ def ComputeSearchDirection(self, obj_grad: KratosOA.CollectiveExpression, constr # solve for inverse of ntn self.linear_solver.Solve(ntn, ntn_inverse, identity_matrix) - search_direction = - (obj_grad - CollectiveListVectorProduct(constr_grad, ntn_inverse * CollectiveListCollectiveProduct(constr_grad, obj_grad))) - correction = - CollectiveListVectorProduct(constr_grad, ntn_inverse * constraint_violations) - correction_norm = KratosOA.ExpressionUtils.NormInf(correction) + search_direction.data[:] = - (obj_grad.data[:] - self._CollectiveListVectorProduct(constr_grad, ntn_inverse * self._CollectiveListCollectiveProduct(constr_grad, obj_grad)).data) + correction.data[:] = - self._CollectiveListVectorProduct(constr_grad, ntn_inverse * constraint_violations).data + + correction_norm = numpy.linalg.norm(correction.data.ravel()) if correction_norm > self.correction_size: - correction *= self.correction_size / correction_norm - self.algorithm_data.GetBufferedData()["search_direction"] = search_direction.Clone() - self.algorithm_data.GetBufferedData()["correction"] = correction.Clone() + correction.data[:] *= self.correction_size / correction_norm + + correction.StoreData() + + self.algorithm_data.GetBufferedData()["search_direction"] = search_direction + self.algorithm_data.GetBufferedData()["correction"] = correction @time_decorator() - def ComputeControlUpdate(self, alpha: float) -> KratosOA.CollectiveExpression: - search_direction = self.algorithm_data.GetBufferedData()["search_direction"] - update = KratosOA.ExpressionUtils.Scale(search_direction, alpha) + self.algorithm_data.GetBufferedData()["correction"] - self.algorithm_data.GetBufferedData()["control_field_update"] = update.Clone() + def ComputeControlUpdate(self, alpha: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor) -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: + search_direction: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor = self.algorithm_data.GetBufferedData()["search_direction"] + update = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(search_direction, perform_collect_data_recursively=False, perform_store_data_recursively=False) + update.data[:] = search_direction.data * alpha.data + self.algorithm_data.GetBufferedData()["correction"].data + Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(update, perform_store_data_recursively=False, copy=False).StoreData() + self.algorithm_data.GetBufferedData()["control_field_update"] = update return update @time_decorator() - def UpdateControl(self) -> KratosOA.CollectiveExpression: - update = self.algorithm_data.GetBufferedData()["control_field_update"] - self._control_field = KratosOA.ExpressionUtils.Collapse(self._control_field + update) + def UpdateControl(self) -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: + update: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor = self.algorithm_data.GetBufferedData()["control_field_update"] + self._control_field.data[:] += update.data + Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(self._control_field, perform_store_data_recursively=False, copy=False).StoreData() @time_decorator() def GetCurrentObjValue(self) -> float: @@ -177,8 +188,8 @@ def GetCurrentControlField(self): return self._control_field @time_decorator() - def Output(self) -> KratosOA.CollectiveExpression: - self.algorithm_data.GetBufferedData()["control_field"] = self._control_field.Clone() + def Output(self) -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: + self.algorithm_data.GetBufferedData()["control_field"] = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(self._control_field) OutputGradientFields(self._objective, self._optimization_problem, True) for constraint in self._constraints_list: OutputGradientFields(constraint, self._optimization_problem, constraint.IsActive()) @@ -318,4 +329,27 @@ def _CreateConvergenceCriteria(self, settings: Kratos.Parameters) -> Convergence or_combined_conv_criteria = CombinedConvCriterion(self.model, combined_params, self._optimization_problem) or_combined_conv_criteria.Add(max_iter_conv_criterion) or_combined_conv_criteria.Add(and_combined_conv_criteria) - return or_combined_conv_criteria \ No newline at end of file + return or_combined_conv_criteria + + + @staticmethod + def _CollectiveListCollectiveProduct(collective_list: 'list[Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]', other_collective: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor) -> Kratos.Vector: + result = Kratos.Vector(len(collective_list)) + for i, collective_list_item in enumerate(collective_list): + result[i] = numpy.dot(collective_list_item.data.ravel(), other_collective.data.ravel()) + return result + + @staticmethod + def _CollectiveListVectorProduct(collective_list: 'list[Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]', vector: Kratos.Vector) -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: + if len(collective_list) != vector.Size(): + raise RuntimeError(f"Collective list size and vector size mismatch. [ Collective list size = {len(collective_list)}, vector size = {vector.Size()}]") + if len(collective_list) == 0: + raise RuntimeError("Collective lists cannot be empty.") + + result = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(collective_list[0], perform_collect_data_recursively=False, perform_store_data_recursively=False) + result.data[:] = 0.0 + for i, collective_list_item in enumerate(collective_list): + result.data[:] += collective_list_item.data * vector[i] + + result.StoreData() + return result \ No newline at end of file diff --git a/applications/OptimizationApplication/tests/algorithm_tests/analysis_based_tests/algorithm_gradient_projection/summary_orig.csv b/applications/OptimizationApplication/tests/algorithm_tests/analysis_based_tests/algorithm_gradient_projection/summary_orig.csv index d30a8e166484..3973aebf5a85 100644 --- a/applications/OptimizationApplication/tests/algorithm_tests/analysis_based_tests/algorithm_gradient_projection/summary_orig.csv +++ b/applications/OptimizationApplication/tests/algorithm_tests/analysis_based_tests/algorithm_gradient_projection/summary_orig.csv @@ -13,14 +13,14 @@ # Headers: # STEP, mass:value, strain_energy:value, strain_energy:std_value 0, 5.887500e+03, 5.004872e+06, 0.000000e+00 - 1, 5.877712e+03, 9.031804e+05, -4.101691e+06 - 2, 5.800649e+03, 1.097727e+06, -3.907144e+06 - 3, 5.738914e+03, 1.207670e+06, -3.797202e+06 - 4, 5.677456e+03, 1.354239e+06, -3.650633e+06 - 5, 5.616447e+03, 1.510429e+06, -3.494443e+06 - 6, 5.555920e+03, 1.687287e+06, -3.317585e+06 - 7, 5.495950e+03, 1.884776e+06, -3.120096e+06 - 8, 5.436598e+03, 2.105923e+06, -2.898948e+06 - 9, 5.377931e+03, 2.353028e+06, -2.651844e+06 - 10, 5.320011e+03, 2.628829e+06, -2.376043e+06 + 1, 5.884177e+03, 9.023825e+05, -4.102489e+06 + 2, 5.824303e+03, 1.031626e+06, -3.973245e+06 + 3, 5.779661e+03, 1.106955e+06, -3.897917e+06 + 4, 5.735094e+03, 1.196828e+06, -3.808043e+06 + 5, 5.690634e+03, 1.292362e+06, -3.712510e+06 + 6, 5.646252e+03, 1.396652e+06, -3.608220e+06 + 7, 5.601936e+03, 1.510277e+06, -3.494595e+06 + 8, 5.557678e+03, 1.634288e+06, -3.370584e+06 + 9, 5.513472e+03, 1.769755e+06, -3.235117e+06 + 10, 5.469317e+03, 1.917869e+06, -3.087003e+06 # End of file \ No newline at end of file From d64e8c7f390d120db46167c0eaa08fa024c78647 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Mon, 9 Feb 2026 13:41:45 +0100 Subject: [PATCH 068/116] update nestrov acc. algo --- ...algorithm_nesterov_accelarated_gradient.py | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/applications/OptimizationApplication/python_scripts/algorithms/algorithm_nesterov_accelarated_gradient.py b/applications/OptimizationApplication/python_scripts/algorithms/algorithm_nesterov_accelarated_gradient.py index 65b8c6a2af9a..20a94b675114 100644 --- a/applications/OptimizationApplication/python_scripts/algorithms/algorithm_nesterov_accelarated_gradient.py +++ b/applications/OptimizationApplication/python_scripts/algorithms/algorithm_nesterov_accelarated_gradient.py @@ -1,5 +1,4 @@ import KratosMultiphysics as Kratos -import KratosMultiphysics.OptimizationApplication as KratosOA from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import time_decorator from KratosMultiphysics.OptimizationApplication.algorithms.algorithm_steepest_descent import AlgorithmSteepestDescent @@ -37,17 +36,21 @@ def __init__(self, model:Kratos.Model, parameters: Kratos.Parameters, optimizati self.eta = self.parameters["settings"]["eta"].GetDouble() @time_decorator() - def ComputeControlUpdate(self, alpha): + def ComputeControlUpdate(self, alpha: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor): # compute the correction part from momentum point - search_direction = self.algorithm_data.GetBufferedData()["search_direction"] - update = KratosOA.ExpressionUtils.Scale(search_direction, alpha) + search_direction: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor = self.algorithm_data.GetBufferedData()["search_direction"] + update = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(search_direction, perform_collect_data_recursively=False, perform_store_data_recursively=False) + update.data[:] *= alpha.data[:] # add momentum to the correction update to compute new momentum point. if self.prev_update: - mom_update = update + self.prev_update * self.eta - self.algorithm_data.GetBufferedData()["control_field_update"] = update + mom_update * self.eta + mom_update = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(update) + mom_update.data[:] += self.prev_update.data * self.eta + control_field_update = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(mom_update) + control_field_update.data[:] = update.data + mom_update.data * self.eta + self.algorithm_data.GetBufferedData()["control_field_update"] = control_field_update self.prev_update = mom_update else: - self.algorithm_data.GetBufferedData()["control_field_update"] = update * (1 + self.eta) + control_field_update = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(update) + control_field_update.data[:] = update.data * (1 + self.eta) + self.algorithm_data.GetBufferedData()["control_field_update"] = control_field_update self.prev_update = update - - self.prev_update = KratosOA.ExpressionUtils.Collapse(self.prev_update) From d5d67a86b6b55700676979a86f9555651575b39d Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Mon, 9 Feb 2026 14:05:31 +0100 Subject: [PATCH 069/116] update relaxed grad algo --- .../algorithm_gradient_projection.py | 3 +- ...algorithm_nesterov_accelarated_gradient.py | 10 ++- .../algorithm_relaxed_gradient_projection.py | 66 ++++++++++--------- .../algorithms/standardized_rgp_constraint.py | 7 +- .../summary_orig.csv | 20 +++--- .../test_relaxed_gradient_projection.py | 14 ++-- 6 files changed, 68 insertions(+), 52 deletions(-) diff --git a/applications/OptimizationApplication/python_scripts/algorithms/algorithm_gradient_projection.py b/applications/OptimizationApplication/python_scripts/algorithms/algorithm_gradient_projection.py index f3825959af97..04700d1b6d3a 100644 --- a/applications/OptimizationApplication/python_scripts/algorithms/algorithm_gradient_projection.py +++ b/applications/OptimizationApplication/python_scripts/algorithms/algorithm_gradient_projection.py @@ -126,9 +126,7 @@ def ComputeSearchDirection(self, obj_grad: Kratos.TensorAdaptors.DoubleCombinedT if not number_of_active_constraints: search_direction.data[:] *= -1.0 - search_direction.StoreData() correction.data[:] = 0.0 - correction.StoreData() else: constraint_violations = Kratos.Vector(number_of_active_constraints) for i, active_constraint in enumerate(active_constraints_list): @@ -159,6 +157,7 @@ def ComputeSearchDirection(self, obj_grad: Kratos.TensorAdaptors.DoubleCombinedT if correction_norm > self.correction_size: correction.data[:] *= self.correction_size / correction_norm + search_direction.StoreData() correction.StoreData() self.algorithm_data.GetBufferedData()["search_direction"] = search_direction diff --git a/applications/OptimizationApplication/python_scripts/algorithms/algorithm_nesterov_accelarated_gradient.py b/applications/OptimizationApplication/python_scripts/algorithms/algorithm_nesterov_accelarated_gradient.py index 20a94b675114..ed097c7fcc2e 100644 --- a/applications/OptimizationApplication/python_scripts/algorithms/algorithm_nesterov_accelarated_gradient.py +++ b/applications/OptimizationApplication/python_scripts/algorithms/algorithm_nesterov_accelarated_gradient.py @@ -41,16 +41,20 @@ def ComputeControlUpdate(self, alpha: Kratos.TensorAdaptors.DoubleCombinedTensor search_direction: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor = self.algorithm_data.GetBufferedData()["search_direction"] update = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(search_direction, perform_collect_data_recursively=False, perform_store_data_recursively=False) update.data[:] *= alpha.data[:] + update.StoreData() # add momentum to the correction update to compute new momentum point. if self.prev_update: - mom_update = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(update) + mom_update = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(update, perform_store_data_recursively=False) mom_update.data[:] += self.prev_update.data * self.eta - control_field_update = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(mom_update) + mom_update.StoreData() + control_field_update = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(mom_update, perform_store_data_recursively=False) control_field_update.data[:] = update.data + mom_update.data * self.eta + control_field_update.StoreData() self.algorithm_data.GetBufferedData()["control_field_update"] = control_field_update self.prev_update = mom_update else: - control_field_update = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(update) + control_field_update = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(update, perform_store_data_recursively=False) control_field_update.data[:] = update.data * (1 + self.eta) + control_field_update.StoreData() self.algorithm_data.GetBufferedData()["control_field_update"] = control_field_update self.prev_update = update diff --git a/applications/OptimizationApplication/python_scripts/algorithms/algorithm_relaxed_gradient_projection.py b/applications/OptimizationApplication/python_scripts/algorithms/algorithm_relaxed_gradient_projection.py index f89eb715fe85..bd1807ed855e 100644 --- a/applications/OptimizationApplication/python_scripts/algorithms/algorithm_relaxed_gradient_projection.py +++ b/applications/OptimizationApplication/python_scripts/algorithms/algorithm_relaxed_gradient_projection.py @@ -1,5 +1,5 @@ +import numpy import KratosMultiphysics as Kratos -import KratosMultiphysics.OptimizationApplication as KratosOA from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem from KratosMultiphysics.OptimizationApplication.algorithms.standardized_objective import StandardizedObjective from KratosMultiphysics.OptimizationApplication.controls.master_control import MasterControl @@ -10,8 +10,6 @@ from KratosMultiphysics.LinearSolversApplication.dense_linear_solver_factory import ConstructSolver from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import time_decorator from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import OptimizationAlgorithmTimeLogger -from KratosMultiphysics.OptimizationApplication.utilities.list_collective_expression_utilities import CollectiveListCollectiveProduct -from KratosMultiphysics.OptimizationApplication.utilities.list_collective_expression_utilities import CollectiveListVectorProduct from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import ListLogger import math @@ -94,36 +92,42 @@ def GetMinimumBufferSize(self) -> int: return self.history_size @time_decorator() - def ComputeSearchDirection(self, obj_grad: KratosOA.CollectiveExpression, constr_grad: 'list[KratosOA.CollectiveExpression]', w_r: Kratos.Vector, w_c: Kratos.Vector) -> KratosOA.CollectiveExpression: + def ComputeSearchDirection(self, obj_grad: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor, constr_grad: 'list[Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]', w_r: Kratos.Vector, w_c: Kratos.Vector) -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: active_constraints_list = self.GetActiveConstraintsList() number_of_active_constraints = len(active_constraints_list) + + search_direction = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(obj_grad, perform_collect_data_recursively=False, perform_store_data_recursively=False) + correction = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(search_direction) + projected_direction = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(search_direction) + if not number_of_active_constraints: - search_direction = obj_grad * -1.0 - correction = obj_grad * 0.0 - projected_direction = obj_grad * 0.0 + search_direction.data[:] = obj_grad.data * -1.0 + correction.data[:] = 0.0 + projected_direction.data[:] = 0.0 else: # scaling obj gradients - obj_norm = KratosOA.ExpressionUtils.NormInf(obj_grad) + obj_norm = numpy.linalg.norm(obj_grad.data.ravel(), ord=numpy.inf) + scaled_obj_grad = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(obj_grad, perform_collect_data_recursively=False, perform_store_data_recursively=False) if not math.isclose(obj_norm, 0.0, abs_tol=1e-16): - scalled_obj_grad = obj_grad / obj_norm - else: - scalled_obj_grad = obj_grad + scaled_obj_grad.data[:] /= obj_norm + scaled_obj_grad.StoreData() - scaled_constr_grad: list[KratosOA.CollectiveExpression] = list() + scaled_constr_grad: 'list[Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]' = [] lagrangian_multiplier = Kratos.Vector(number_of_active_constraints) for i in range(number_of_active_constraints): # scaling constraints grad - norm = KratosOA.ExpressionUtils.NormInf(constr_grad[i]) + norm = numpy.linalg.norm(constr_grad[i].data.ravel(), ord=numpy.inf) + ta = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(constr_grad[i], perform_collect_data_recursively=False, perform_store_data_recursively=False) + scaled_constr_grad.append(ta) if not math.isclose(norm, 0.0, abs_tol=1e-16): - scaled_constr_grad.append( constr_grad[i] / norm ) - else: - scaled_constr_grad.append( constr_grad[i] ) + ta.data[:] /= norm + ta.StoreData() # compute the projected search direction and correction ntn = Kratos.Matrix(number_of_active_constraints, number_of_active_constraints) for i in range(number_of_active_constraints): for j in range(i, number_of_active_constraints): - ntn[i, j] = KratosOA.ExpressionUtils.InnerProduct(scaled_constr_grad[i], scaled_constr_grad[j]) + ntn[i, j] = numpy.dot(scaled_constr_grad[i].data.ravel(), scaled_constr_grad[j].data.ravel()) ntn[j, i] = ntn[i, j] # get the inverse of ntn @@ -137,18 +141,18 @@ def ComputeSearchDirection(self, obj_grad: KratosOA.CollectiveExpression, constr # solve for inverse of ntn self.linear_solver.Solve(ntn, ntn_inverse, identity_matrix) - lagrangian_multiplier = ntn_inverse * CollectiveListCollectiveProduct(scaled_constr_grad, scalled_obj_grad) + lagrangian_multiplier = ntn_inverse * self._CollectiveListCollectiveProduct(scaled_constr_grad, scaled_obj_grad) for i in range(number_of_active_constraints): if lagrangian_multiplier[i] > 0.0: lagrangian_multiplier[i] = 0.0 else: lagrangian_multiplier[i] *= w_r[i] - projected_direction = - (scalled_obj_grad - CollectiveListVectorProduct(scaled_constr_grad, lagrangian_multiplier)) - correction = - CollectiveListVectorProduct(scaled_constr_grad, w_c) - search_direction = projected_direction + correction - self.algorithm_data.GetBufferedData().SetValue("search_direction", search_direction.Clone(), overwrite=True) - self.algorithm_data.GetBufferedData().SetValue("correction", correction.Clone(), overwrite=True) - self.algorithm_data.GetBufferedData().SetValue("projected_direction", projected_direction.Clone(), overwrite=True) + projected_direction.data[:] = - (scaled_obj_grad.data - self._CollectiveListVectorProduct(scaled_constr_grad, lagrangian_multiplier).data) + correction.data[:] = - self._CollectiveListVectorProduct(scaled_constr_grad, w_c).data + search_direction.data[:] = projected_direction.data + correction.data + self.algorithm_data.GetBufferedData().SetValue("search_direction", search_direction, overwrite=True) + self.algorithm_data.GetBufferedData().SetValue("correction", correction, overwrite=True) + self.algorithm_data.GetBufferedData().SetValue("projected_direction", projected_direction, overwrite=True) def ComputeBufferCoefficients(self): active_constraints_list = self.GetActiveConstraintsList() @@ -166,17 +170,19 @@ def ComputeBufferCoefficients(self): return w_r, w_c @time_decorator() - def ComputeControlUpdate(self, alpha) -> KratosOA.CollectiveExpression: - search_direction = self.algorithm_data.GetBufferedData()["search_direction"] - update = KratosOA.ExpressionUtils.Scale(search_direction, alpha) - self.algorithm_data.GetBufferedData().SetValue("control_field_update", update.Clone(), overwrite=True) + def ComputeControlUpdate(self, alpha: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor) -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: + search_direction: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor = self.algorithm_data.GetBufferedData()["search_direction"] + update = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(search_direction, perform_collect_data_recursively=False, perform_store_data_recursively=False) + update.data[:] = search_direction.data * alpha.data + update.StoreData() + self.algorithm_data.GetBufferedData().SetValue("control_field_update", update, overwrite=True) return update - def CheckLinearizedConstraints(self, active_constr_grad: 'list[KratosOA.CollectiveExpression]', update: KratosOA.CollectiveExpression, w_r, w_c) -> bool: + def CheckLinearizedConstraints(self, active_constr_grad: 'list[Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]', update: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor, w_r, w_c) -> bool: all_feasible = True active_constraints_list = self.GetActiveConstraintsList() for i, constraint in enumerate(active_constraints_list): - predicted_value = constraint.GetStandardizedValue() + KratosOA.ExpressionUtils.InnerProduct(active_constr_grad[i], update) + predicted_value = constraint.GetStandardizedValue() + numpy.dot(active_constr_grad[i].data.ravel(), update.data.ravel()) print(f"RGP Constraint {constraint.GetResponseName()}:: predicted g_i {predicted_value}") if not constraint.IsSatisfied(predicted_value): all_feasible = False diff --git a/applications/OptimizationApplication/python_scripts/algorithms/standardized_rgp_constraint.py b/applications/OptimizationApplication/python_scripts/algorithms/standardized_rgp_constraint.py index a8fba2f171fd..15a0ce7a726d 100644 --- a/applications/OptimizationApplication/python_scripts/algorithms/standardized_rgp_constraint.py +++ b/applications/OptimizationApplication/python_scripts/algorithms/standardized_rgp_constraint.py @@ -198,7 +198,7 @@ def GetReferenceValue(self) -> float: else: raise RuntimeError(f"Response value for {self.GetResponseName()} is not calculated yet.") - def CalculateStandardizedValue(self, control_field: KratosOA.CollectiveExpression, save_value: bool = True) -> float: + def CalculateStandardizedValue(self, control_field: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor, save_value: bool = True) -> float: with TimeLogger(f"StandardizedRGPConstraint::Calculate {self.GetResponseName()} value", None, "Finished"): response_value = self.CalculateValue(control_field) standardized_response_value = response_value * self.__scaling @@ -218,14 +218,15 @@ def CalculateStandardizedValue(self, control_field: KratosOA.CollectiveExpressio return standardized_response_value - def CalculateStandardizedGradient(self) -> KratosOA.CollectiveExpression: + def CalculateStandardizedGradient(self) -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: with TimeLogger(f"StandardizedRGPConstraint::Calculate {self.GetResponseName()} gradients", None, "Finished"): gradient_collective_expression = self.CalculateGradient() if self.IsEqualityType(): factor = 1.0 if self.GetStandardizedValue() > 0.0 else -1.0 else: factor = 1.0 - return gradient_collective_expression * self.__scaling * factor + gradient_collective_expression.data[:] *= self.__scaling * factor + return gradient_collective_expression def GetValue(self, step_index: int = 0) -> float: return self.__buffered_data.GetValue("value", step_index) diff --git a/applications/OptimizationApplication/tests/algorithm_tests/analysis_based_tests/algorithm_relaxed_gradient_projection/summary_orig.csv b/applications/OptimizationApplication/tests/algorithm_tests/analysis_based_tests/algorithm_relaxed_gradient_projection/summary_orig.csv index 5a74a974eaf8..e6e8c1d14721 100644 --- a/applications/OptimizationApplication/tests/algorithm_tests/analysis_based_tests/algorithm_relaxed_gradient_projection/summary_orig.csv +++ b/applications/OptimizationApplication/tests/algorithm_tests/analysis_based_tests/algorithm_relaxed_gradient_projection/summary_orig.csv @@ -13,14 +13,14 @@ # Headers: # STEP, mass:value, strain_energy:value, strain_energy:std_value 0, 5.887500e+03, 5.004872e+06, 0.000000e+00 - 1, 5.877712e+03, 9.031804e+05, -4.101691e+06 - 2, 5.819053e+03, 1.035807e+06, -3.969065e+06 - 3, 5.776169e+03, 1.085432e+06, -3.919440e+06 - 4, 5.733628e+03, 1.145764e+06, -3.859107e+06 - 5, 5.691533e+03, 1.206921e+06, -3.797951e+06 - 6, 5.649862e+03, 1.271146e+06, -3.733725e+06 - 7, 5.608626e+03, 1.338458e+06, -3.666413e+06 - 8, 5.567833e+03, 1.409084e+06, -3.595788e+06 - 9, 5.527498e+03, 1.483221e+06, -3.521650e+06 - 10, 5.487634e+03, 1.561076e+06, -3.443796e+06 + 1, 5.884177e+03, 9.023825e+05, -4.102489e+06 + 2, 5.837676e+03, 9.912807e+05, -4.013591e+06 + 3, 5.806628e+03, 1.026025e+06, -3.978847e+06 + 4, 5.775717e+03, 1.065228e+06, -3.939644e+06 + 5, 5.744952e+03, 1.105246e+06, -3.899626e+06 + 6, 5.714293e+03, 1.146828e+06, -3.858044e+06 + 7, 5.683715e+03, 1.190088e+06, -3.814784e+06 + 8, 5.653194e+03, 1.235183e+06, -3.769689e+06 + 9, 5.622713e+03, 1.282273e+06, -3.722598e+06 + 10, 5.592254e+03, 1.331530e+06, -3.673342e+06 # End of file \ No newline at end of file diff --git a/applications/OptimizationApplication/tests/algorithm_tests/analysis_based_tests/algorithm_relaxed_gradient_projection/test_relaxed_gradient_projection.py b/applications/OptimizationApplication/tests/algorithm_tests/analysis_based_tests/algorithm_relaxed_gradient_projection/test_relaxed_gradient_projection.py index 7fd604d61931..96a393824673 100644 --- a/applications/OptimizationApplication/tests/algorithm_tests/analysis_based_tests/algorithm_relaxed_gradient_projection/test_relaxed_gradient_projection.py +++ b/applications/OptimizationApplication/tests/algorithm_tests/analysis_based_tests/algorithm_relaxed_gradient_projection/test_relaxed_gradient_projection.py @@ -46,7 +46,10 @@ def test_gradient_projection_components(self): value = constraint.CalculateStandardizedValue(control_field) w = constraint.ComputeW() self.assertAlmostEqual(w, 1.0) - value = constraint.CalculateStandardizedValue(control_field * 2) + cta = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(control_field, perform_store_data_recursively=False) + cta.data[:] *= 2.0 + cta.StoreData() + value = constraint.CalculateStandardizedValue(cta) constraint.UpdateBufferSize() w = constraint.ComputeW() self.assertAlmostEqual(w, 0.0) @@ -58,14 +61,17 @@ def test_gradient_projection_components(self): self.assertAlmostEqual(constraint.CF, 1) algorithm._optimization_problem.AdvanceStep() - value = constraint.CalculateStandardizedValue(control_field*0.5) + cta = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(control_field, perform_store_data_recursively=False) + cta.data[:] *= 0.001 + cta.StoreData() + value = constraint.CalculateStandardizedValue(cta) constraint.UpdateBufferSize() w = constraint.ComputeW() - self.assertAlmostEqual(w, 1.472738040151665) + self.assertAlmostEqual(w, 0.6714966387273962) self.assertAlmostEqual(constraint.BSF, 2.0) self.assertAlmostEqual(constraint.BSF_init, 2.0) self.assertAlmostEqual(constraint.CBV, 0.0) - self.assertAlmostEqual(int(constraint.BS), 143622435) + self.assertAlmostEqual(int(constraint.BS), 4885031) self.assertAlmostEqual(constraint.max_w_c, 10) self.assertAlmostEqual(constraint.CF, 1) From cbf94e8bf70b9b104a0d5b9ac1c622718f6542f5 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Tue, 10 Feb 2026 07:20:25 +0100 Subject: [PATCH 070/116] add clone --- .../python/add_tensor_adaptors_to_python.cpp | 84 ++++----- .../combined_tensor_adaptor.cpp | 48 ++++- .../tensor_adaptors/combined_tensor_adaptor.h | 11 +- .../connectivity_ids_tensor_adaptor.cpp | 5 + .../connectivity_ids_tensor_adaptor.h | 8 + .../equation_ids_tensor_adaptor.cpp | 5 + .../equation_ids_tensor_adaptor.h | 7 + .../tensor_adaptors/flags_tensor_adaptor.cpp | 5 + kratos/tensor_adaptors/flags_tensor_adaptor.h | 7 + .../gauss_point_variable_tensor_adaptor.cpp | 5 + .../gauss_point_variable_tensor_adaptor.h | 7 + .../geometries_tensor_adaptor.cpp | 5 + .../geometries_tensor_adaptor.h | 57 +++--- .../geometry_metrics_tensor_adaptor.cpp | 5 + .../geometry_metrics_tensor_adaptor.h | 7 + .../historical_variable_tensor_adaptor.cpp | 5 + .../historical_variable_tensor_adaptor.h | 7 + .../nodal_neighbour_count_tensor_adaptor.cpp | 5 + .../nodal_neighbour_count_tensor_adaptor.h | 7 + .../node_position_tensor_adaptor.cpp | 5 + .../node_position_tensor_adaptor.h | 7 + kratos/tensor_adaptors/tensor_adaptor.cpp | 6 + kratos/tensor_adaptors/tensor_adaptor.h | 5 + .../variable_tensor_adaptor.cpp | 5 + .../tensor_adaptors/variable_tensor_adaptor.h | 7 + kratos/tests/test_tensor_adaptors.py | 173 ++++++++++++++++-- 26 files changed, 415 insertions(+), 83 deletions(-) diff --git a/kratos/python/add_tensor_adaptors_to_python.cpp b/kratos/python/add_tensor_adaptors_to_python.cpp index f7f4ea341d31..4c7514c55a63 100644 --- a/kratos/python/add_tensor_adaptors_to_python.cpp +++ b/kratos/python/add_tensor_adaptors_to_python.cpp @@ -51,43 +51,43 @@ void AddBaseTensorAdaptor( pybind11::module& rModule, const std::string& rName) { - // add the base tensor adaptor - using tensor_adaptor = TensorAdaptor; - pybind11::class_( - rModule, (rName + "Adaptor").c_str()) - .def(pybind11::init::Pointer, const bool>(), - pybind11::arg("container"), - pybind11::arg("nd_data"), - pybind11::arg("copy") = true) - .def(pybind11::init(), - pybind11::arg("tensor_adaptor"), - pybind11::arg("copy") = true) - .def("Check", &tensor_adaptor::Check) - .def("CollectData", &tensor_adaptor::CollectData) - .def("StoreData", &tensor_adaptor::StoreData) - .def("GetContainer", &tensor_adaptor::GetContainer) - .def("HasContainer", &tensor_adaptor::HasContainer) - .def("Shape", &tensor_adaptor::Shape) - .def("DataShape", &tensor_adaptor::DataShape) - .def("Size", &tensor_adaptor::Size) - .def("__str__", PrintObject) - .def("ViewData", [](tensor_adaptor& rSelf) { return GetPybindArray(*rSelf.pGetStorage()); }) - .def("SetData", [](tensor_adaptor& rSelf, const pybind11::array& rArray) { SetPybindArray(*rSelf.pGetStorage(), rArray); }, - pybind11::arg("array").noconvert()) - .def_property("data", - [](tensor_adaptor& rSelf) { - return GetPybindArray(*rSelf.pGetStorage()); - }, - pybind11::cpp_function( - [](tensor_adaptor& rSelf, const pybind11::array& rArray) { + // add the base tensor adaptor + using tensor_adaptor = TensorAdaptor; + pybind11::class_(rModule, (rName + "Adaptor").c_str()) + .def(pybind11::init::Pointer, const bool>(), + pybind11::arg("container"), + pybind11::arg("nd_data"), + pybind11::arg("copy") = true) + .def(pybind11::init(), + pybind11::arg("tensor_adaptor"), + pybind11::arg("copy") = true) + .def("Clone", &tensor_adaptor::Clone) + .def("Check", &tensor_adaptor::Check) + .def("CollectData", &tensor_adaptor::CollectData) + .def("StoreData", &tensor_adaptor::StoreData) + .def("GetContainer", &tensor_adaptor::GetContainer) + .def("HasContainer", &tensor_adaptor::HasContainer) + .def("Shape", &tensor_adaptor::Shape) + .def("DataShape", &tensor_adaptor::DataShape) + .def("Size", &tensor_adaptor::Size) + .def("__str__", PrintObject) + .def("ViewData", [](tensor_adaptor& rSelf) { return GetPybindArray(*rSelf.pGetStorage()); }) + .def("SetData", [](tensor_adaptor& rSelf, const pybind11::array& rArray) { SetPybindArray(*rSelf.pGetStorage(), rArray); }, + pybind11::arg("array").noconvert()) + .def_property("data", + [](tensor_adaptor& rSelf) { + return GetPybindArray(*rSelf.pGetStorage()); + }, + pybind11::cpp_function( + [](tensor_adaptor& rSelf, const pybind11::array& rArray) { SetPybindArray(*rSelf.pGetStorage(), rArray); - }, - pybind11::arg("self"), - // no convert makes sure that the numpy arrays are - // not converted, hence nothing will be copied. numpy - // array will be passed as it is to the SetPybindArray - // method. - pybind11::arg("array").noconvert())); + }, + pybind11::arg("self"), + // no convert makes sure that the numpy arrays are + // not converted, hence nothing will be copied. numpy + // array will be passed as it is to the SetPybindArray + // method. + pybind11::arg("array").noconvert())); } template @@ -97,16 +97,18 @@ void AddCombinedTensorAdaptor( { using combined_ta_type = CombinedTensorAdaptor; pybind11::class_(rModule, rName.c_str()) - .def(pybind11::init(), + .def(pybind11::init(), pybind11::arg("list_of_tensor_adaptors"), pybind11::arg("perform_collect_data_recursively") = true, - pybind11::arg("perform_store_data_recursively") = true) // reveling ctor - .def(pybind11::init(), + pybind11::arg("perform_store_data_recursively") = true, + pybind11::arg("copy") = true) // reveling ctor + .def(pybind11::init(), pybind11::arg("list_of_tensor_adaptors"), pybind11::arg("axis"), pybind11::arg("perform_collect_data_recursively") = true, - pybind11::arg("perform_store_data_recursively") = true) // axis based ctor + pybind11::arg("perform_store_data_recursively") = true, + pybind11::arg("copy") = true) // axis based ctor .def(pybind11::init(), - pybind11::arg("list_of_tensor_adaptors"), + pybind11::arg("combined_tensor_adaptor"), pybind11::arg("perform_collect_data_recursively") = true, pybind11::arg("perform_store_data_recursively") = true, pybind11::arg("copy") = true) diff --git a/kratos/tensor_adaptors/combined_tensor_adaptor.cpp b/kratos/tensor_adaptors/combined_tensor_adaptor.cpp index a6edad5e1a0e..1506f5d3b135 100644 --- a/kratos/tensor_adaptors/combined_tensor_adaptor.cpp +++ b/kratos/tensor_adaptors/combined_tensor_adaptor.cpp @@ -42,14 +42,22 @@ CombinedTensorAdaptor::CombinedTensorAdaptor( const TensorAdaptorVectorType& rTensorAdaptorVector, const unsigned int Axis, const bool PerformCollectDataRecursively, - const bool PerformStoreDataRecursively) + const bool PerformStoreDataRecursively, + const bool Copy) : mPerformCollectDataRecursively(PerformCollectDataRecursively), mPerformStoreDataRecursively(PerformStoreDataRecursively), - mAxis(Axis), - mTensorAdaptors(rTensorAdaptorVector) + mAxis(Axis) { KRATOS_TRY + for (const auto& p_tensor_adaptor : rTensorAdaptorVector) { + if (Copy) { + mTensorAdaptors.push_back(p_tensor_adaptor->Clone()); + } else { + mTensorAdaptors.push_back(p_tensor_adaptor); + } + } + // It is not allowed to create combined tensor adaptors with empty list of tensor adaptors vector KRATOS_ERROR_IF(rTensorAdaptorVector.empty()) << "Creating a CombinedTensorAdaptor with empty list of tensor adaptors is not allowed."; @@ -110,14 +118,22 @@ template CombinedTensorAdaptor::CombinedTensorAdaptor( const TensorAdaptorVectorType& rTensorAdaptorVector, const bool PerformCollectDataRecursively, - const bool PerformStoreDataRecursively) + const bool PerformStoreDataRecursively, + const bool Copy) : mPerformCollectDataRecursively(PerformCollectDataRecursively), mPerformStoreDataRecursively(PerformStoreDataRecursively), - mAxis(-1), // represent that this combined tensor adaptor is used with ravel - mTensorAdaptors(rTensorAdaptorVector) + mAxis(-1) // represent that this combined tensor adaptor is used with ravel { KRATOS_TRY + for (const auto& p_tensor_adaptor : rTensorAdaptorVector) { + if (Copy) { + mTensorAdaptors.push_back(p_tensor_adaptor->Clone()); + } else { + mTensorAdaptors.push_back(p_tensor_adaptor); + } + } + // this combined tensor will have everything raveled. Therefore, it will only have one dimension. DenseVector tensor_shape(1); @@ -141,9 +157,25 @@ CombinedTensorAdaptor::CombinedTensorAdaptor( : BaseType(rOther, Copy), mPerformCollectDataRecursively(PerformCollectDataRecursively), mPerformStoreDataRecursively(PerformStoreDataRecursively), - mAxis(rOther.mAxis), - mTensorAdaptors(rOther.mTensorAdaptors) + mAxis(rOther.mAxis) +{ + KRATOS_TRY + + for (const auto& p_tensor_adaptor : rOther.mTensorAdaptors) { + if (Copy) { + mTensorAdaptors.push_back(p_tensor_adaptor->Clone()); + } else { + mTensorAdaptors.push_back(p_tensor_adaptor); + } + } + + KRATOS_CATCH(""); +} + +template +typename TensorAdaptor::Pointer CombinedTensorAdaptor::Clone() const { + return Kratos::make_shared>(*this, this->mPerformCollectDataRecursively, this->mPerformStoreDataRecursively); } template diff --git a/kratos/tensor_adaptors/combined_tensor_adaptor.h b/kratos/tensor_adaptors/combined_tensor_adaptor.h index fa8b3aaeec26..04c5b72ece2e 100644 --- a/kratos/tensor_adaptors/combined_tensor_adaptor.h +++ b/kratos/tensor_adaptors/combined_tensor_adaptor.h @@ -156,7 +156,8 @@ class KRATOS_API(KRATOS_CORE) CombinedTensorAdaptor : public TensorAdaptor::Pointer Clone() const override; + /** * @brief Check if the necessary data is present in the underlying container. * @details This method should not change anything in the underlying Kratos data structures. It should diff --git a/kratos/tensor_adaptors/connectivity_ids_tensor_adaptor.cpp b/kratos/tensor_adaptors/connectivity_ids_tensor_adaptor.cpp index 45993d4d9c14..2f73908bb1ea 100644 --- a/kratos/tensor_adaptors/connectivity_ids_tensor_adaptor.cpp +++ b/kratos/tensor_adaptors/connectivity_ids_tensor_adaptor.cpp @@ -114,6 +114,11 @@ void ConnectivityIdsTensorAdaptor::Check() const { *mpContainer); } +TensorAdaptor::Pointer ConnectivityIdsTensorAdaptor::Clone() const +{ + return Kratos::make_shared(*this); +} + void ConnectivityIdsTensorAdaptor::CollectData() { const auto &shape = mpStorage->Shape(); diff --git a/kratos/tensor_adaptors/connectivity_ids_tensor_adaptor.h b/kratos/tensor_adaptors/connectivity_ids_tensor_adaptor.h index bd9b68a1ba9a..2b72633032a9 100644 --- a/kratos/tensor_adaptors/connectivity_ids_tensor_adaptor.h +++ b/kratos/tensor_adaptors/connectivity_ids_tensor_adaptor.h @@ -68,13 +68,21 @@ class KRATOS_API(KRATOS_CORE) ConnectivityIdsTensorAdaptor ConnectivityIdsTensorAdaptor(const BaseType &rOther, const bool Copy = true); + ConnectivityIdsTensorAdaptor(const ConnectivityIdsTensorAdaptor& rOther) = default; + // Destructor ~ConnectivityIdsTensorAdaptor() override = default; + ///@} ///@name Public operations ///@{ + /** + * @brief Clones the existing tensor adaptor. + */ + TensorAdaptor::Pointer Clone() const override; + /** * @brief Check if the container is valid. */ diff --git a/kratos/tensor_adaptors/equation_ids_tensor_adaptor.cpp b/kratos/tensor_adaptors/equation_ids_tensor_adaptor.cpp index 6a9639ba14d1..d0e5db7cab96 100644 --- a/kratos/tensor_adaptors/equation_ids_tensor_adaptor.cpp +++ b/kratos/tensor_adaptors/equation_ids_tensor_adaptor.cpp @@ -99,6 +99,11 @@ EquationIdsTensorAdaptor::EquationIdsTensorAdaptor( KRATOS_CATCH(""); } +TensorAdaptor::Pointer EquationIdsTensorAdaptor::Clone() const +{ + return Kratos::make_shared(*this); +} + void EquationIdsTensorAdaptor::CollectData() { KRATOS_TRY diff --git a/kratos/tensor_adaptors/equation_ids_tensor_adaptor.h b/kratos/tensor_adaptors/equation_ids_tensor_adaptor.h index a51c11d977bf..8f674041ab9e 100644 --- a/kratos/tensor_adaptors/equation_ids_tensor_adaptor.h +++ b/kratos/tensor_adaptors/equation_ids_tensor_adaptor.h @@ -74,6 +74,8 @@ class KRATOS_API(KRATOS_CORE) EquationIdsTensorAdaptor: public TensorAdaptor::Pointer FlagsTensorAdaptor::Clone() const +{ + return Kratos::make_shared(*this); +} + void FlagsTensorAdaptor::CollectData() { std::visit([this](auto pContainer) { diff --git a/kratos/tensor_adaptors/flags_tensor_adaptor.h b/kratos/tensor_adaptors/flags_tensor_adaptor.h index bd627d97ccf9..47c0d8567d1f 100644 --- a/kratos/tensor_adaptors/flags_tensor_adaptor.h +++ b/kratos/tensor_adaptors/flags_tensor_adaptor.h @@ -82,6 +82,8 @@ class KRATOS_API(KRATOS_CORE) FlagsTensorAdaptor: public TensorAdaptor { const Flags& rFlags, const bool Copy = true); + FlagsTensorAdaptor(const FlagsTensorAdaptor& rOther) = default; + // Destructor ~FlagsTensorAdaptor() override = default; @@ -89,6 +91,11 @@ class KRATOS_API(KRATOS_CORE) FlagsTensorAdaptor: public TensorAdaptor { ///@name Public operations ///@{ + /** + * @brief Clones the existing tensor adaptor. + */ + TensorAdaptor::Pointer Clone() const override; + void Check() const override; /** diff --git a/kratos/tensor_adaptors/gauss_point_variable_tensor_adaptor.cpp b/kratos/tensor_adaptors/gauss_point_variable_tensor_adaptor.cpp index 06303754a174..1f18f1683803 100644 --- a/kratos/tensor_adaptors/gauss_point_variable_tensor_adaptor.cpp +++ b/kratos/tensor_adaptors/gauss_point_variable_tensor_adaptor.cpp @@ -80,6 +80,11 @@ GaussPointVariableTensorAdaptor::GaussPointVariableTensorAdaptor( KRATOS_CATCH(""); } +TensorAdaptor::Pointer GaussPointVariableTensorAdaptor::Clone() const +{ + return Kratos::make_shared(*this); +} + void GaussPointVariableTensorAdaptor::CollectData() { std::visit([this](auto pContainer, auto pVariable) { diff --git a/kratos/tensor_adaptors/gauss_point_variable_tensor_adaptor.h b/kratos/tensor_adaptors/gauss_point_variable_tensor_adaptor.h index c500ef2d46dd..8397e17d333c 100644 --- a/kratos/tensor_adaptors/gauss_point_variable_tensor_adaptor.h +++ b/kratos/tensor_adaptors/gauss_point_variable_tensor_adaptor.h @@ -79,6 +79,8 @@ class KRATOS_API(KRATOS_CORE) GaussPointVariableTensorAdaptor: public TensorAdap ProcessInfo::Pointer pProcessInfo, const bool Copy = true); + GaussPointVariableTensorAdaptor(const GaussPointVariableTensorAdaptor& rOther) = default; + // Destructor ~GaussPointVariableTensorAdaptor() override = default; @@ -86,6 +88,11 @@ class KRATOS_API(KRATOS_CORE) GaussPointVariableTensorAdaptor: public TensorAdap ///@name Public operations ///@{ + /** + * @brief Clones the existing tensor adaptor. + */ + TensorAdaptor::Pointer Clone() const override; + /** * @brief Fill the internal data from Kratos data structures */ diff --git a/kratos/tensor_adaptors/geometries_tensor_adaptor.cpp b/kratos/tensor_adaptors/geometries_tensor_adaptor.cpp index e444349ed418..2f453adf6a3a 100644 --- a/kratos/tensor_adaptors/geometries_tensor_adaptor.cpp +++ b/kratos/tensor_adaptors/geometries_tensor_adaptor.cpp @@ -297,6 +297,11 @@ GeometriesTensorAdaptor::GeometriesTensorAdaptor( *mpContainer); } +TensorAdaptor::Pointer GeometriesTensorAdaptor::Clone() const +{ + return Kratos::make_shared(*this); +} + void GeometriesTensorAdaptor::Check() const {} void GeometriesTensorAdaptor::CollectData() diff --git a/kratos/tensor_adaptors/geometries_tensor_adaptor.h b/kratos/tensor_adaptors/geometries_tensor_adaptor.h index 3a97a31a3275..1918c12aa70e 100644 --- a/kratos/tensor_adaptors/geometries_tensor_adaptor.h +++ b/kratos/tensor_adaptors/geometries_tensor_adaptor.h @@ -74,14 +74,18 @@ class KRATOS_API(KRATOS_CORE) GeometriesTensorAdaptor ///@{ GeometriesTensorAdaptor( - ContainerPointerType pContainer, DatumType Datum, - GeometryData::IntegrationMethod IntegrationMethod = - GeometryData::IntegrationMethod::NumberOfIntegrationMethods); + ContainerPointerType pContainer, + DatumType Datum, + GeometryData::IntegrationMethod IntegrationMethod = GeometryData::IntegrationMethod::NumberOfIntegrationMethods); - GeometriesTensorAdaptor(const TensorAdaptor &rOther, - ContainerPointerType pContainer, DatumType Datum, - GeometryData::IntegrationMethod IntegrationMethod, - const bool Copy = true); + GeometriesTensorAdaptor( + const TensorAdaptor &rOther, + ContainerPointerType pContainer, + DatumType Datum, + GeometryData::IntegrationMethod IntegrationMethod, + const bool Copy = true); + + GeometriesTensorAdaptor(const GeometriesTensorAdaptor& rOther) = default; // Destructor ~GeometriesTensorAdaptor() override = default; @@ -90,6 +94,11 @@ class KRATOS_API(KRATOS_CORE) GeometriesTensorAdaptor ///@name Public operations ///@{ + /** + * @brief Clones the existing tensor adaptor. + */ + TensorAdaptor::Pointer Clone() const override; + /** * @brief Check if the container is valid. */ @@ -146,33 +155,39 @@ class KRATOS_API(KRATOS_CORE) GeometriesTensorAdaptor template static void CollectIntegrationWeights( - double* pData, const TContainerType& rContainer, + double* pData, + const TContainerType& rContainer, GeometryData::IntegrationMethod Method, const DenseVector& Shape); template - static void CollectShapeFunctions(double* pData, - const TContainerType& rContainer, - GeometryData::IntegrationMethod Method, - const DenseVector& Shape); + static void CollectShapeFunctions( + double* pData, + const TContainerType& rContainer, + GeometryData::IntegrationMethod Method, + const DenseVector& Shape); template static void CollectShapeFunctionsDerivatives( - double* pData, const TContainerType& rContainer, + double* pData, + const TContainerType& rContainer, GeometryData::IntegrationMethod Method, const DenseVector& Shape); template - static void CollectJacobians(double* pData, - const TContainerType& rContainer, - GeometryData::IntegrationMethod Method, - const DenseVector& Shape); + static void CollectJacobians( + double* pData, + const TContainerType& rContainer, + GeometryData::IntegrationMethod Method, + const DenseVector& Shape); template - static void FillData(double* pData, const TContainerType& rContainer, - GeometriesTensorAdaptor::DatumType Datum, - GeometryData::IntegrationMethod Method, - const DenseVector& Shape); + static void FillData( + double* pData, + const TContainerType& rContainer, + GeometriesTensorAdaptor::DatumType Datum, + GeometryData::IntegrationMethod Method, + const DenseVector& Shape); DatumType mDatum; GeometryData::IntegrationMethod mIntegrationMethod; diff --git a/kratos/tensor_adaptors/geometry_metrics_tensor_adaptor.cpp b/kratos/tensor_adaptors/geometry_metrics_tensor_adaptor.cpp index 02a5e64d408e..866530656942 100644 --- a/kratos/tensor_adaptors/geometry_metrics_tensor_adaptor.cpp +++ b/kratos/tensor_adaptors/geometry_metrics_tensor_adaptor.cpp @@ -113,6 +113,11 @@ GeometryMetricsTensorAdaptor::GeometryMetricsTensorAdaptor( KRATOS_CATCH(""); } +TensorAdaptor::Pointer GeometryMetricsTensorAdaptor::Clone() const +{ + return Kratos::make_shared(*this); +} + void GeometryMetricsTensorAdaptor::CollectData() { KRATOS_TRY diff --git a/kratos/tensor_adaptors/geometry_metrics_tensor_adaptor.h b/kratos/tensor_adaptors/geometry_metrics_tensor_adaptor.h index c263adf77013..c223c3d4d382 100644 --- a/kratos/tensor_adaptors/geometry_metrics_tensor_adaptor.h +++ b/kratos/tensor_adaptors/geometry_metrics_tensor_adaptor.h @@ -78,6 +78,8 @@ class KRATOS_API(KRATOS_CORE) GeometryMetricsTensorAdaptor: public TensorAdaptor const DatumType Datum, const bool Copy = true); + GeometryMetricsTensorAdaptor(const GeometryMetricsTensorAdaptor& rOther) = default; + // Destructor ~GeometryMetricsTensorAdaptor() override = default; @@ -85,6 +87,11 @@ class KRATOS_API(KRATOS_CORE) GeometryMetricsTensorAdaptor: public TensorAdaptor ///@name Public operations ///@{ + /** + * @brief Clones the existing tensor adaptor. + */ + TensorAdaptor::Pointer Clone() const override; + /** * @brief Fill the internal data with number of neightour entities of nodes * @details This will fill the internal data for each node with its available number of entities (i.e. conditions / elements). diff --git a/kratos/tensor_adaptors/historical_variable_tensor_adaptor.cpp b/kratos/tensor_adaptors/historical_variable_tensor_adaptor.cpp index 31da0c43b15f..ae69f257b092 100644 --- a/kratos/tensor_adaptors/historical_variable_tensor_adaptor.cpp +++ b/kratos/tensor_adaptors/historical_variable_tensor_adaptor.cpp @@ -119,6 +119,11 @@ HistoricalVariableTensorAdaptor::HistoricalVariableTensorAdaptor( KRATOS_CATCH(""); } +TensorAdaptor::Pointer HistoricalVariableTensorAdaptor::Clone() const +{ + return Kratos::make_shared(*this); +} + void HistoricalVariableTensorAdaptor::Check() const { KRATOS_TRY diff --git a/kratos/tensor_adaptors/historical_variable_tensor_adaptor.h b/kratos/tensor_adaptors/historical_variable_tensor_adaptor.h index 3846ce450d5a..4febb352f250 100644 --- a/kratos/tensor_adaptors/historical_variable_tensor_adaptor.h +++ b/kratos/tensor_adaptors/historical_variable_tensor_adaptor.h @@ -85,6 +85,8 @@ class KRATOS_API(KRATOS_CORE) HistoricalVariableTensorAdaptor: public TensorAdap const int StepIndex = 0, const bool Copy = true); + HistoricalVariableTensorAdaptor(const HistoricalVariableTensorAdaptor& rOther) = default; + // Destructor ~HistoricalVariableTensorAdaptor() override = default; @@ -92,6 +94,11 @@ class KRATOS_API(KRATOS_CORE) HistoricalVariableTensorAdaptor: public TensorAdap ///@name Public operations ///@{ + /** + * @brief Clones the existing tensor adaptor. + */ + TensorAdaptor::Pointer Clone() const override; + /** * @brief Checks if the given variable is available and the buffer size is enough in each node. */ diff --git a/kratos/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.cpp b/kratos/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.cpp index 409c65ba3770..089133947266 100644 --- a/kratos/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.cpp +++ b/kratos/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.cpp @@ -56,6 +56,11 @@ NodalNeighbourCountTensorAdaptor::NodalNeighbourCountTensorAdaptor( KRATOS_CATCH(""); } +TensorAdaptor::Pointer NodalNeighbourCountTensorAdaptor::Clone() const +{ + return Kratos::make_shared(*this); +} + void NodalNeighbourCountTensorAdaptor::CollectData() { KRATOS_TRY diff --git a/kratos/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.h b/kratos/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.h index 8079f8dc1c01..132a219b57ea 100644 --- a/kratos/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.h +++ b/kratos/tensor_adaptors/nodal_neighbour_count_tensor_adaptor.h @@ -71,6 +71,8 @@ class KRATOS_API(KRATOS_CORE) NodalNeighbourCountTensorAdaptor: public TensorAda TContainerPointerType pEntityContainer, const bool Copy = true); + NodalNeighbourCountTensorAdaptor(const NodalNeighbourCountTensorAdaptor& rOther) = default; + // Destructor ~NodalNeighbourCountTensorAdaptor() override = default; @@ -78,6 +80,11 @@ class KRATOS_API(KRATOS_CORE) NodalNeighbourCountTensorAdaptor: public TensorAda ///@name Public operations ///@{ + /** + * @brief Clones the existing tensor adaptor. + */ + TensorAdaptor::Pointer Clone() const override; + /** * @brief Fill the internal data with number of neightour entities of nodes * @details This will fill the internal data for each node with its available number of entities (i.e. conditions / elements). diff --git a/kratos/tensor_adaptors/node_position_tensor_adaptor.cpp b/kratos/tensor_adaptors/node_position_tensor_adaptor.cpp index ade60c17bdfc..25747fa59347 100644 --- a/kratos/tensor_adaptors/node_position_tensor_adaptor.cpp +++ b/kratos/tensor_adaptors/node_position_tensor_adaptor.cpp @@ -80,6 +80,11 @@ NodePositionTensorAdaptor::NodePositionTensorAdaptor( KRATOS_CATCH(""); } +TensorAdaptor::Pointer NodePositionTensorAdaptor::Clone() const +{ + return Kratos::make_shared(*this); +} + void NodePositionTensorAdaptor::CollectData() { KRATOS_TRY diff --git a/kratos/tensor_adaptors/node_position_tensor_adaptor.h b/kratos/tensor_adaptors/node_position_tensor_adaptor.h index ef813d525b97..e39478eb4161 100644 --- a/kratos/tensor_adaptors/node_position_tensor_adaptor.h +++ b/kratos/tensor_adaptors/node_position_tensor_adaptor.h @@ -80,6 +80,8 @@ class KRATOS_API(KRATOS_CORE) NodePositionTensorAdaptor: public TensorAdaptor::TensorAdaptor( this->mpContainer = rOther.mpContainer; } +template +typename TensorAdaptor::Pointer TensorAdaptor::Clone() const +{ + return Kratos::make_shared>(*this); +} + template void TensorAdaptor::Check() const { diff --git a/kratos/tensor_adaptors/tensor_adaptor.h b/kratos/tensor_adaptors/tensor_adaptor.h index 6096e5950988..ce41f79eb70a 100644 --- a/kratos/tensor_adaptors/tensor_adaptor.h +++ b/kratos/tensor_adaptors/tensor_adaptor.h @@ -155,6 +155,11 @@ class KRATOS_API(KRATOS_CORE) TensorAdaptor { ///@name Public operations ///@{ + /** + * @brief Clones the existing tensor adaptor. + */ + virtual TensorAdaptor::Pointer Clone() const; + /** * @brief Check if the necessary data is present in the underlying container. * @details This method should not change anything in the underlying Kratos data structures. It should diff --git a/kratos/tensor_adaptors/variable_tensor_adaptor.cpp b/kratos/tensor_adaptors/variable_tensor_adaptor.cpp index c47352167dc5..ec4d476fa809 100644 --- a/kratos/tensor_adaptors/variable_tensor_adaptor.cpp +++ b/kratos/tensor_adaptors/variable_tensor_adaptor.cpp @@ -88,6 +88,11 @@ VariableTensorAdaptor::VariableTensorAdaptor( KRATOS_CATCH(""); } +TensorAdaptor::Pointer VariableTensorAdaptor::Clone() const +{ + return Kratos::make_shared(*this); +} + void VariableTensorAdaptor::Check() const { KRATOS_TRY diff --git a/kratos/tensor_adaptors/variable_tensor_adaptor.h b/kratos/tensor_adaptors/variable_tensor_adaptor.h index f7bd00f655db..a7552d872253 100644 --- a/kratos/tensor_adaptors/variable_tensor_adaptor.h +++ b/kratos/tensor_adaptors/variable_tensor_adaptor.h @@ -88,6 +88,8 @@ class KRATOS_API(KRATOS_CORE) VariableTensorAdaptor: public TensorAdaptor Date: Tue, 10 Feb 2026 07:23:02 +0100 Subject: [PATCH 071/116] update momentum algo --- ...hm_momentum_relaxed_gradient_projection.py | 26 ++++++++++++------- .../algorithms/standardized_rgp_constraint.py | 6 ++--- .../list_collective_expression_utilities.py | 22 ---------------- 3 files changed, 20 insertions(+), 34 deletions(-) delete mode 100644 applications/OptimizationApplication/python_scripts/utilities/list_collective_expression_utilities.py diff --git a/applications/OptimizationApplication/python_scripts/algorithms/algorithm_momentum_relaxed_gradient_projection.py b/applications/OptimizationApplication/python_scripts/algorithms/algorithm_momentum_relaxed_gradient_projection.py index 1a6515e4c349..d449bf823907 100644 --- a/applications/OptimizationApplication/python_scripts/algorithms/algorithm_momentum_relaxed_gradient_projection.py +++ b/applications/OptimizationApplication/python_scripts/algorithms/algorithm_momentum_relaxed_gradient_projection.py @@ -42,21 +42,29 @@ def __init__(self, model:Kratos.Model, parameters: Kratos.Parameters, optimizati self.eta = self.parameters["settings"]["eta"].GetDouble() @time_decorator() - def ComputeControlUpdate(self, alpha): + def ComputeControlUpdate(self, alpha: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor): # compute the correction part from momentum point - search_direction = self.algorithm_data.GetBufferedData()["search_direction"] - update = KratosOA.ExpressionUtils.Scale(search_direction, alpha) + search_direction: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor = self.algorithm_data.GetBufferedData()["search_direction"] + update = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(search_direction, perform_store_data_recursively=False) + update.data[:] *= alpha.data + update.StoreData() # add momentum to the correction update to compute new momentum point. if self.prev_update: - mom_update = update + self.prev_update * self.eta - full_update = update + mom_update * self.eta - self.prev_update = KratosOA.ExpressionUtils.Collapse(mom_update) + mom_update = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(update, perform_store_data_recursively=False) + mom_update.data[:] += self.prev_update.data * self.eta + mom_update.StoreData() + + full_update = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(update, perform_collect_data_recursively=False) + full_update.data[:] += mom_update.data * self.eta + full_update.StoreData() + self.prev_update = mom_update else: - full_update = update * (1 + self.eta) + full_update = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(update, perform_collect_data_recursively=False) + full_update.data[:] *= (1 + self.eta) + full_update.StoreData() self.prev_update = update - self.algorithm_data.GetBufferedData().SetValue("control_field_update", full_update.Clone(), overwrite=True) + self.algorithm_data.GetBufferedData().SetValue("control_field_update", full_update, overwrite=True) - self.prev_update = KratosOA.ExpressionUtils.Collapse(self.prev_update) return full_update diff --git a/applications/OptimizationApplication/python_scripts/algorithms/standardized_rgp_constraint.py b/applications/OptimizationApplication/python_scripts/algorithms/standardized_rgp_constraint.py index 15a0ce7a726d..bf1fff3d05e3 100644 --- a/applications/OptimizationApplication/python_scripts/algorithms/standardized_rgp_constraint.py +++ b/applications/OptimizationApplication/python_scripts/algorithms/standardized_rgp_constraint.py @@ -220,13 +220,13 @@ def CalculateStandardizedValue(self, control_field: Kratos.TensorAdaptors.Double def CalculateStandardizedGradient(self) -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: with TimeLogger(f"StandardizedRGPConstraint::Calculate {self.GetResponseName()} gradients", None, "Finished"): - gradient_collective_expression = self.CalculateGradient() + gradient_cta = self.CalculateGradient() if self.IsEqualityType(): factor = 1.0 if self.GetStandardizedValue() > 0.0 else -1.0 else: factor = 1.0 - gradient_collective_expression.data[:] *= self.__scaling * factor - return gradient_collective_expression + gradient_cta.data[:] *= self.__scaling * factor + return gradient_cta def GetValue(self, step_index: int = 0) -> float: return self.__buffered_data.GetValue("value", step_index) diff --git a/applications/OptimizationApplication/python_scripts/utilities/list_collective_expression_utilities.py b/applications/OptimizationApplication/python_scripts/utilities/list_collective_expression_utilities.py deleted file mode 100644 index bc66b1820f6e..000000000000 --- a/applications/OptimizationApplication/python_scripts/utilities/list_collective_expression_utilities.py +++ /dev/null @@ -1,22 +0,0 @@ -import KratosMultiphysics as Kratos -import KratosMultiphysics.OptimizationApplication as KratosOA - - -def CollectiveListCollectiveProduct(collective_list: 'list[KratosOA.CollectiveExpression]', other_collective: KratosOA.CollectiveExpression) -> Kratos.Vector: - result = Kratos.Vector(len(collective_list)) - - for i, collective_list_item in enumerate(collective_list): - result[i] = KratosOA.ExpressionUtils.InnerProduct(collective_list_item, other_collective) - return result - -def CollectiveListVectorProduct(collective_list: 'list[KratosOA.CollectiveExpression]', vector: Kratos.Vector) -> KratosOA.CollectiveExpression: - if len(collective_list) != vector.Size(): - raise RuntimeError(f"Collective list size and vector size mismatch. [ Collective list size = {len(collective_list)}, vector size = {vector.Size()}]") - if len(collective_list) == 0: - raise RuntimeError("Collective lists cannot be empty.") - - result = collective_list[0] * 0.0 - for i, collective_list_item in enumerate(collective_list): - result += collective_list_item * vector[i] - - return result \ No newline at end of file From f1d9bad9d54970b1b0529af0bcda9056644fba02 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Tue, 10 Feb 2026 15:31:08 +0100 Subject: [PATCH 072/116] update steepest descent --- .../algorithms/algorithm_steepest_descent.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/applications/OptimizationApplication/python_scripts/algorithms/algorithm_steepest_descent.py b/applications/OptimizationApplication/python_scripts/algorithms/algorithm_steepest_descent.py index 2fe64f5a5c8c..584935f0e166 100644 --- a/applications/OptimizationApplication/python_scripts/algorithms/algorithm_steepest_descent.py +++ b/applications/OptimizationApplication/python_scripts/algorithms/algorithm_steepest_descent.py @@ -91,16 +91,15 @@ def Finalize(self) -> None: @time_decorator() def ComputeSearchDirection(self, obj_grad: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor) -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: - search_direction = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(obj_grad) - search_direction.data[:] = obj_grad.data[:] * -1.0 + search_direction: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor = obj_grad.Clone() + search_direction.data[:] *= -1.0 Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(search_direction, perform_store_data_recursively=False, copy=False).StoreData() - self.algorithm_data.GetBufferedData()["search_direction"] = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(search_direction) + self.algorithm_data.GetBufferedData()["search_direction"] = search_direction return search_direction @time_decorator() def ComputeControlUpdate(self, alpha: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor) -> None: - search_direction: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor = self.algorithm_data.GetBufferedData()["search_direction"] - update = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(search_direction) + update: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor = self.algorithm_data.GetBufferedData()["search_direction"].Clone() update.data[:] *= alpha.data[:] Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(update, perform_store_data_recursively=False, copy=False).StoreData() self.algorithm_data.GetBufferedData()["control_field_update"] = update From da75bcebf1694cb04eaaabcaacc7168dd35fa9cc Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Tue, 10 Feb 2026 15:36:20 +0100 Subject: [PATCH 073/116] update mat prop control --- .../controls/material/material_properties_control.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/OptimizationApplication/python_scripts/controls/material/material_properties_control.py b/applications/OptimizationApplication/python_scripts/controls/material/material_properties_control.py index e51babab0243..4c36977ad07a 100644 --- a/applications/OptimizationApplication/python_scripts/controls/material/material_properties_control.py +++ b/applications/OptimizationApplication/python_scripts/controls/material/material_properties_control.py @@ -89,7 +89,7 @@ def MapGradient(self, physical_gradient_variable_tensor_adaptor_map: 'dict[Suppo raise RuntimeError(f"Gradients for the required element container not found for control \"{self.GetName()}\". [ required model part name: {self.model_part.FullName()} ]") # TODO: Implement filtering mechanisms here - return Kratos.TensorAdaptors.DoubleTensorAdaptor(physical_gradient_variable_tensor_adaptor_map[self.controlled_physical_variable]) + return physical_gradient_variable_tensor_adaptor_map[self.controlled_physical_variable].Clone() def Update(self, control_field: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> bool: if control_field.GetContainer() != self.GetEmptyField().GetContainer(): From 868bf222f0697278fd17fa52e03d48518d4abe89 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Tue, 10 Feb 2026 17:14:08 +0100 Subject: [PATCH 074/116] use clone in controls --- .../python_scripts/controls/material/simp_control.py | 6 +++--- .../controls/shape/vertex_morphing_shape_control.py | 2 +- .../controls/thickness/shell_thickness_control.py | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/applications/OptimizationApplication/python_scripts/controls/material/simp_control.py b/applications/OptimizationApplication/python_scripts/controls/material/simp_control.py index 972a396087b2..9c2968ddf0c3 100644 --- a/applications/OptimizationApplication/python_scripts/controls/material/simp_control.py +++ b/applications/OptimizationApplication/python_scripts/controls/material/simp_control.py @@ -223,8 +223,8 @@ def _UpdateAndOutputFields(self, update: Kratos.TensorAdaptors.DoubleTensorAdapt # now output the fields un_buffered_data = ComponentDataView(self, self.optimization_problem).GetUnBufferedData() - un_buffered_data.SetValue(f"{self.GetName()}", Kratos.TensorAdaptors.DoubleTensorAdaptor(self.simp_physical_phi),overwrite=True) + un_buffered_data.SetValue(f"{self.GetName()}", self.simp_physical_phi.Clone(),overwrite=True) if self.output_all_fields: un_buffered_data.SetValue(f"{self.GetName()}_update", physical_phi_update, overwrite=True) - un_buffered_data.SetValue(f"dDENSITY_d{self.GetName()}", Kratos.TensorAdaptors.DoubleTensorAdaptor(self.d_density_d_phi), overwrite=True) - un_buffered_data.SetValue(f"dYOUNG_MODULUS_d{self.GetName()}", Kratos.TensorAdaptors.DoubleTensorAdaptor(self.d_young_modulus_d_phi), overwrite=True) + un_buffered_data.SetValue(f"dDENSITY_d{self.GetName()}", self.d_density_d_phi.Clone(), overwrite=True) + un_buffered_data.SetValue(f"dYOUNG_MODULUS_d{self.GetName()}", self.d_young_modulus_d_phi.Clone(), overwrite=True) diff --git a/applications/OptimizationApplication/python_scripts/controls/shape/vertex_morphing_shape_control.py b/applications/OptimizationApplication/python_scripts/controls/shape/vertex_morphing_shape_control.py index dc70541789ca..830699ed8d7a 100644 --- a/applications/OptimizationApplication/python_scripts/controls/shape/vertex_morphing_shape_control.py +++ b/applications/OptimizationApplication/python_scripts/controls/shape/vertex_morphing_shape_control.py @@ -174,7 +174,7 @@ def _UpdateAndOutputFields(self, control_update: Kratos.TensorAdaptors.DoubleTen un_buffered_data = ComponentDataView(self, self.optimization_problem).GetUnBufferedData() un_buffered_data.SetValue("shape_update", shape_update,overwrite=True) if self.output_all_fields: - un_buffered_data.SetValue("shape_control", Kratos.TensorAdaptors.DoubleTensorAdaptor(self.control_field), overwrite=True) + un_buffered_data.SetValue("shape_control", self.control_field.Clone(), overwrite=True) un_buffered_data.SetValue("shape_control_update", control_update, overwrite=True) def _UpdateMesh(self, shape_update: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> None: diff --git a/applications/OptimizationApplication/python_scripts/controls/thickness/shell_thickness_control.py b/applications/OptimizationApplication/python_scripts/controls/thickness/shell_thickness_control.py index 1344d649f87e..f2070bb59bbd 100644 --- a/applications/OptimizationApplication/python_scripts/controls/thickness/shell_thickness_control.py +++ b/applications/OptimizationApplication/python_scripts/controls/thickness/shell_thickness_control.py @@ -175,9 +175,9 @@ def _UpdateAndOutputFields(self, update: Kratos.TensorAdaptors.DoubleTensorAdapt un_buffered_data.SetValue("physical_thickness", projected_filtered_thickness_field,overwrite=True) if self.output_all_fields: un_buffered_data.SetValue("filtered_thickness_update", filtered_thickness_field_update, overwrite=True) - un_buffered_data.SetValue("control_thickness_phi", Kratos.TensorAdaptors.DoubleTensorAdaptor(self.control_phi_field), overwrite=True) - un_buffered_data.SetValue("physical_thickness_phi", Kratos.TensorAdaptors.DoubleTensorAdaptor(self.physical_phi_field), overwrite=True) - un_buffered_data.SetValue("projection_derivative", Kratos.TensorAdaptors.DoubleTensorAdaptor(self.projection_derivative_field), overwrite=True) + un_buffered_data.SetValue("control_thickness_phi", self.control_phi_field.Clone(), overwrite=True) + un_buffered_data.SetValue("physical_thickness_phi", self.physical_phi_field.Clone(), overwrite=True) + un_buffered_data.SetValue("projection_derivative", self.projection_derivative_field.Clone(), overwrite=True) def __str__(self) -> str: return f"Control [type = {self.__class__.__name__}, name = {self.GetName()}, model part name = {self.model_part.FullName()}, control variable = {Kratos.THICKNESS.Name()}" From 6fe424ca66eff7f27cbace4ecf1e3a0cf148e66a Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Wed, 11 Feb 2026 00:07:55 +0100 Subject: [PATCH 075/116] minor --- .../controls/shape/vertex_morphing_shape_control.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/OptimizationApplication/python_scripts/controls/shape/vertex_morphing_shape_control.py b/applications/OptimizationApplication/python_scripts/controls/shape/vertex_morphing_shape_control.py index 830699ed8d7a..0b65f851a1fe 100644 --- a/applications/OptimizationApplication/python_scripts/controls/shape/vertex_morphing_shape_control.py +++ b/applications/OptimizationApplication/python_scripts/controls/shape/vertex_morphing_shape_control.py @@ -175,7 +175,7 @@ def _UpdateAndOutputFields(self, control_update: Kratos.TensorAdaptors.DoubleTen un_buffered_data.SetValue("shape_update", shape_update,overwrite=True) if self.output_all_fields: un_buffered_data.SetValue("shape_control", self.control_field.Clone(), overwrite=True) - un_buffered_data.SetValue("shape_control_update", control_update, overwrite=True) + un_buffered_data.SetValue("shape_control_update", control_update.Clone(), overwrite=True) def _UpdateMesh(self, shape_update: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> None: if self.mesh_motion_solver_type != "none": From 4c8f86671cde195f4ebe96de3690ee92b3b7ef7a Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Wed, 11 Feb 2026 00:19:41 +0100 Subject: [PATCH 076/116] update external resp func --- .../external_response_function_control.py | 48 +++++++++---------- .../responses/external_response_function.py | 17 +++---- .../tests/test_external_response_function.py | 6 +-- 3 files changed, 36 insertions(+), 35 deletions(-) diff --git a/applications/OptimizationApplication/python_scripts/controls/external_response_function_control.py b/applications/OptimizationApplication/python_scripts/controls/external_response_function_control.py index cb315cf86689..d8a57a21c8c8 100644 --- a/applications/OptimizationApplication/python_scripts/controls/external_response_function_control.py +++ b/applications/OptimizationApplication/python_scripts/controls/external_response_function_control.py @@ -1,3 +1,4 @@ +import numpy from typing import Optional import KratosMultiphysics as Kratos from KratosMultiphysics.OptimizationApplication.controls.control import Control @@ -7,9 +8,7 @@ from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes -from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import ContainerExpressionTypes from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import TimeLogger -from KratosMultiphysics.OptimizationApplication.utilities.helper_utilities import IsSameContainerExpression def Factory(model: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem) -> Control: if not parameters.Has("name"): @@ -57,8 +56,8 @@ def Initialize(self) -> None: self.filter.SetComponentDataView(ComponentDataView(self, self.optimization_problem)) self.filter.Initialize() - self.physical_phi_field = Kratos.Expression.NodalExpression(self.model_part) - Kratos.Expression.VariableExpressionIO.Read(self.physical_phi_field, self.design_variable, False) + self.physical_phi_field = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, self.design_variable) + self.physical_phi_field.CollectData() if self.filter: # take the physical and control field the same @@ -80,24 +79,24 @@ def Finalize(self) -> None: def GetPhysicalKratosVariables(self) -> 'list[SupportedSensitivityFieldVariableTypes]': return [self.design_variable] - def GetEmptyField(self) -> ContainerExpressionTypes: - exp = Kratos.Expression.NodalExpression(self.model_part) - Kratos.Expression.LiteralExpressionIO.SetDataToZero(exp, self.design_variable) - return exp + def GetEmptyField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + ta = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, self.design_variable) + ta.data[:] = 0.0 + return ta - def GetControlField(self) -> ContainerExpressionTypes: - return self.control_phi_field + def GetControlField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + return self.control_phi_field.Clone() - def MapGradient(self, physical_gradient_variable_container_expression_map: 'dict[SupportedSensitivityFieldVariableTypes, ContainerExpressionTypes]') -> ContainerExpressionTypes: + def MapGradient(self, physical_gradient_variable_tensor_adaptor_map: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleTensorAdaptor]') -> Kratos.TensorAdaptors.DoubleTensorAdaptor: with TimeLogger("ExternalResponseFunctionControl::MapGradient", None, "Finished",False): - keys = physical_gradient_variable_container_expression_map.keys() + keys = physical_gradient_variable_tensor_adaptor_map.keys() if len(keys) != 1: raise RuntimeError(f"Provided more than required gradient fields for control \"{self.GetName()}\". Following are the variables:\n\t" + "\n\t".join([k.Name() for k in keys])) if self.design_variable not in keys: raise RuntimeError(f"The required gradient for control \"{self.GetName()}\" w.r.t. {self.design_variable.Name()} not found. Followings are the variables:\n\t" + "\n\t".join([k.Name() for k in keys])) - physical_gradient = physical_gradient_variable_container_expression_map[self.design_variable] - if not IsSameContainerExpression(physical_gradient, self.GetEmptyField()): + physical_gradient = physical_gradient_variable_tensor_adaptor_map[self.design_variable] + if physical_gradient.GetContainer() != self.model_part.Nodes: raise RuntimeError(f"Gradients for the required container not found for control \"{self.GetName()}\". [ required model part name: {self.model_part.FullName()}, given model part name: {physical_gradient.GetModelPart().FullName()} ]") if self.filter: @@ -108,15 +107,16 @@ def MapGradient(self, physical_gradient_variable_container_expression_map: 'dict return filtered_gradient - def Update(self, new_control_field: ContainerExpressionTypes) -> bool: - if not IsSameContainerExpression(new_control_field, self.GetEmptyField()): - raise RuntimeError(f"Updates for the required container not found for control \"{self.GetName()}\". [ required model part name: {self.model_part.FullName()}, given model part name: {new_control_field.GetModelPart().FullName()} ]") + def Update(self, new_control_field: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> bool: + if new_control_field.GetContainer() != self.model_part.Nodes: + raise RuntimeError(f"Updates for the required container not found for control \"{self.GetName()}\". [ required model part name: {self.model_part.FullName()} ]") - update = new_control_field - self.control_phi_field - if Kratos.Expression.Utils.NormL2(update) > 1e-15: + update = new_control_field.Clone() + update.data[:] -= self.control_phi_field.data + if numpy.linalg.norm(update.data) > 1e-15: with TimeLogger(self.__class__.__name__, f"Updating {self.GetName()}...", f"Finished updating of {self.GetName()}.",False): # update the control thickness field - self.control_phi_field = new_control_field + self.control_phi_field.data[:] = new_control_field.data # now update the physical field self._UpdateAndOutputFields(update) @@ -125,19 +125,19 @@ def Update(self, new_control_field: ContainerExpressionTypes) -> bool: return True return False - def _UpdateAndOutputFields(self, update: ContainerExpressionTypes) -> None: + def _UpdateAndOutputFields(self, update: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> None: if self.filter: # filter the control field filtered_update = self.filter.ForwardFilterField(update) else: filtered_update = update.Clone() - self.physical_phi_field = Kratos.Expression.Utils.Collapse(self.physical_phi_field + filtered_update) - Kratos.Expression.VariableExpressionIO.Write(self.physical_phi_field, self.design_variable, False) + self.physical_phi_field.data[:] += filtered_update.data + Kratos.TensorAdaptors.VariableTensorAdaptor(self.physical_phi_field, self.design_variable, copy=False).StoreData() # add the values of the control to the optimization problem. component_data_view = ComponentDataView(self, self.optimization_problem) - for i, v in enumerate(self.physical_phi_field.Evaluate()): + for i, v in enumerate(self.physical_phi_field.data): component_data_view.GetBufferedData().SetValue(f"{self.model_part.FullName()}_point_{i+1}", float(v)) # now output the fields diff --git a/applications/OptimizationApplication/python_scripts/responses/external_response_function.py b/applications/OptimizationApplication/python_scripts/responses/external_response_function.py index e5948ad85675..a4d7bde84ff3 100644 --- a/applications/OptimizationApplication/python_scripts/responses/external_response_function.py +++ b/applications/OptimizationApplication/python_scripts/responses/external_response_function.py @@ -52,16 +52,17 @@ def _GetDesignVariableValues(self) -> 'dict[str, numpy.ndarray]': # get the values from the model part nodal non-historical container result: 'dict[str, numpy.ndarray]' = {} for mp_name in self.model_part_operation.list_of_operation_model_part_full_names: - exp = Kratos.Expression.NodalExpression(self.model[mp_name]) - Kratos.Expression.VariableExpressionIO.Read(exp, KratosOA.CUSTOM_DESIGN_VARIABLE, False) - result[mp_name] = exp.Evaluate() + ta = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model[mp_name].Nodes, KratosOA.CUSTOM_DESIGN_VARIABLE) + ta.CollectData() + result[mp_name] = ta.data return result - def _UpdateGradientsFromNumpy(self, numpy_values_map: 'dict[str, numpy.ndarray]', physical_variable_collective_expressions: 'dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]') -> None: + def _UpdateGradientsFromNumpy(self, numpy_values_map: 'dict[str, numpy.ndarray]', physical_variable_combined_tensor_adaptor: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]') -> None: for i, mp_name in enumerate(self.model_part_operation.list_of_operation_model_part_full_names): - # assign the sensitivities to the physical_variable_collective_expressions - Kratos.Expression.CArrayExpressionIO.Read(physical_variable_collective_expressions[KratosOA.CUSTOM_DESIGN_VARIABLE].GetContainerExpressions()[i], numpy_values_map[mp_name]) + # assign the sensitivities to the physical_variable_combined_tensor_adaptor + physical_variable_combined_tensor_adaptor[KratosOA.CUSTOM_DESIGN_VARIABLE].GetTensorAdaptors()[i].data[:] = numpy_values_map[mp_name] + Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(physical_variable_combined_tensor_adaptor[KratosOA.CUSTOM_DESIGN_VARIABLE], perform_collect_data_recursively=False, copy=False).CollectData() def CalculateValue(self) -> float: numpy_values = self._GetDesignVariableValues()[self.model_part_operation.list_of_operation_model_part_full_names[0]] @@ -71,7 +72,7 @@ def CalculateValue(self) -> float: return float((numpy_values[0]-2) ** 2 + (numpy_values[1]-3) ** 2 + (numpy_values[2]-4) ** 2 + (numpy_values[3]-5))**2 - def CalculateGradient(self, physical_variable_collective_expressions: 'dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]') -> None: + def CalculateGradient(self, physical_variable_combined_tensor_adaptor: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]') -> None: numpy_values = self._GetDesignVariableValues()[self.model_part_operation.list_of_operation_model_part_full_names[0]] # compute the gradients @@ -83,4 +84,4 @@ def CalculateGradient(self, physical_variable_collective_expressions: 'dict[Supp # create the numpy array of sensitivities numpy_exp_map = {self.model_part_operation.list_of_operation_model_part_full_names[0]: numpy.array([df_dx0, df_dx1, df_dx2, df_dx3])} - self._UpdateGradientsFromNumpy(numpy_exp_map, physical_variable_collective_expressions) + self._UpdateGradientsFromNumpy(numpy_exp_map, physical_variable_combined_tensor_adaptor) diff --git a/applications/OptimizationApplication/tests/test_external_response_function.py b/applications/OptimizationApplication/tests/test_external_response_function.py index e3bba841710d..0ec911bf869b 100644 --- a/applications/OptimizationApplication/tests/test_external_response_function.py +++ b/applications/OptimizationApplication/tests/test_external_response_function.py @@ -15,10 +15,10 @@ def test_steepest_descent_analysis(self): analysis.Run() model_part = model["CustomMP"] - exp = Kratos.Expression.NodalExpression(model_part) - Kratos.Expression.VariableExpressionIO.Read(exp, KratosOA.CUSTOM_DESIGN_VARIABLE, False) + ta = Kratos.TensorAdaptors.VariableTensorAdaptor(model_part.Nodes, KratosOA.CUSTOM_DESIGN_VARIABLE) + ta.CollectData() - self.assertVectorAlmostEqual(exp.Evaluate(), [2,3,4,5]) + self.assertVectorAlmostEqual(ta.data, [2,3,4,5]) if __name__ == "__main__": kratos_unittest.main() From cd3c87e01e5275e555c38e0d2209d597e7e65cae Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Wed, 11 Feb 2026 00:23:15 +0100 Subject: [PATCH 077/116] update opt prob ascii output process test --- ...test_optimization_problem_ascii_output_process.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/applications/OptimizationApplication/tests/process_tests/test_optimization_problem_ascii_output_process.py b/applications/OptimizationApplication/tests/process_tests/test_optimization_problem_ascii_output_process.py index 4f8698fda9c3..1ed8b07f775a 100644 --- a/applications/OptimizationApplication/tests/process_tests/test_optimization_problem_ascii_output_process.py +++ b/applications/OptimizationApplication/tests/process_tests/test_optimization_problem_ascii_output_process.py @@ -9,7 +9,7 @@ from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView from KratosMultiphysics.OptimizationApplication.utilities.buffered_dict import BufferedDict from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem -from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import ContainerExpressionTypes, SupportedSensitivityFieldVariableTypes +from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes from KratosMultiphysics.compare_two_files_check_process import CompareTwoFilesCheckProcess class TestOptimizationProblemAsciiOutputProcess(kratos_unittest.TestCase): @@ -18,7 +18,7 @@ def __init__(self, response_name: str) -> None: super().__init__(response_name) def CalculateValue(self) -> float: return 0.0 - def CalculateGradient(self, physical_variable_collective_expressions: 'dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]') -> None: + def CalculateGradient(self, physical_variable_combined_tensor_adaptor: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]') -> None: pass def Check(self) -> None: pass @@ -40,15 +40,15 @@ def Initialize(self) -> None: pass def Finalize(self) -> None: pass - def GetControlField(self) -> ContainerExpressionTypes: + def GetControlField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: return None - def GetEmptyField(self) -> ContainerExpressionTypes: + def GetEmptyField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: return None def GetPhysicalKratosVariables(self) -> 'list[SupportedSensitivityFieldVariableTypes]': return [] - def MapGradient(self, physical_gradient_variable_container_expression_map: 'dict[SupportedSensitivityFieldVariableTypes, ContainerExpressionTypes]') -> ContainerExpressionTypes: + def MapGradient(self, physical_gradient_variable_container_expression_map: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleTensorAdaptor]') -> Kratos.TensorAdaptors.DoubleTensorAdaptor: return None - def Update(self, control_field: ContainerExpressionTypes) -> bool: + def Update(self, control_field: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> bool: return True class DummyExecutionPolicy(ExecutionPolicy): From caba02f3072bffce68d8abd6d4abc0df5baf3e3b Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Wed, 11 Feb 2026 00:23:43 +0100 Subject: [PATCH 078/116] minor --- .../test_optimization_problem_ascii_output_process.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/OptimizationApplication/tests/process_tests/test_optimization_problem_ascii_output_process.py b/applications/OptimizationApplication/tests/process_tests/test_optimization_problem_ascii_output_process.py index 1ed8b07f775a..fbf355662af6 100644 --- a/applications/OptimizationApplication/tests/process_tests/test_optimization_problem_ascii_output_process.py +++ b/applications/OptimizationApplication/tests/process_tests/test_optimization_problem_ascii_output_process.py @@ -46,7 +46,7 @@ def GetEmptyField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: return None def GetPhysicalKratosVariables(self) -> 'list[SupportedSensitivityFieldVariableTypes]': return [] - def MapGradient(self, physical_gradient_variable_container_expression_map: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleTensorAdaptor]') -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + def MapGradient(self, physical_gradient_variable_tensor_adaptor_map: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleTensorAdaptor]') -> Kratos.TensorAdaptors.DoubleTensorAdaptor: return None def Update(self, control_field: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> bool: return True From 8a5b95f6ed51a1c78b2e8116d5897788776955ac Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Wed, 11 Feb 2026 10:03:56 +0100 Subject: [PATCH 079/116] fix conv criterion --- .../properties_variable_tensor_adaptor.cpp | 5 +++++ .../properties_variable_tensor_adaptor.h | 5 +++++ .../convergence_criteria/l2_conv_criterion.py | 8 +++---- .../tests/algorithm_tests/test_convergence.py | 21 +++++++++++-------- 4 files changed, 26 insertions(+), 13 deletions(-) diff --git a/applications/OptimizationApplication/custom_utilities/tensor_adaptors/properties_variable_tensor_adaptor.cpp b/applications/OptimizationApplication/custom_utilities/tensor_adaptors/properties_variable_tensor_adaptor.cpp index 29ad3550acb7..bc6500c70f19 100644 --- a/applications/OptimizationApplication/custom_utilities/tensor_adaptors/properties_variable_tensor_adaptor.cpp +++ b/applications/OptimizationApplication/custom_utilities/tensor_adaptors/properties_variable_tensor_adaptor.cpp @@ -86,6 +86,11 @@ PropertiesVariableTensorAdaptor::PropertiesVariableTensorAdaptor( KRATOS_CATCH(""); } +TensorAdaptor::Pointer PropertiesVariableTensorAdaptor::Clone() const +{ + return Kratos::make_shared(*this, mpVariable, true); +} + void PropertiesVariableTensorAdaptor::Check() const { KRATOS_TRY diff --git a/applications/OptimizationApplication/custom_utilities/tensor_adaptors/properties_variable_tensor_adaptor.h b/applications/OptimizationApplication/custom_utilities/tensor_adaptors/properties_variable_tensor_adaptor.h index fa62bd875340..f3b6617ec3b4 100644 --- a/applications/OptimizationApplication/custom_utilities/tensor_adaptors/properties_variable_tensor_adaptor.h +++ b/applications/OptimizationApplication/custom_utilities/tensor_adaptors/properties_variable_tensor_adaptor.h @@ -88,6 +88,11 @@ class KRATOS_API(OPTIMIZATION_APPLICATION) PropertiesVariableTensorAdaptor: publ ///@name Public operations ///@{ + /** + * @brief Clones the existing tensor adaptor. + */ + TensorAdaptor::Pointer Clone() const override; + /** * @brief Execution of this check is only required if this PropertiesVariableTensorAdaptor * will be used to call the @ref CollectData method. If it is only required to be called diff --git a/applications/OptimizationApplication/python_scripts/convergence_criteria/l2_conv_criterion.py b/applications/OptimizationApplication/python_scripts/convergence_criteria/l2_conv_criterion.py index ef4e54aa3fe4..98822b6519de 100644 --- a/applications/OptimizationApplication/python_scripts/convergence_criteria/l2_conv_criterion.py +++ b/applications/OptimizationApplication/python_scripts/convergence_criteria/l2_conv_criterion.py @@ -1,4 +1,4 @@ -import typing +import typing, numpy import KratosMultiphysics as Kratos import KratosMultiphysics.OptimizationApplication as KratosOA from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem @@ -52,12 +52,12 @@ def Initialize(self): @time_decorator() def IsConverged(self) -> bool: - field = GetComponentValueByFullName(self.__component_data_view, self.__field_name) + field: Kratos.TensorAdaptors.DoubleTensorAdaptor = GetComponentValueByFullName(self.__component_data_view, self.__field_name) - if not hasattr(field, "Evaluate"): + if not hasattr(field, "data"): raise RuntimeError(f"The value represented by {self.__field_name} is not a field.") - self.__norm = KratosOA.ExpressionUtils.NormL2(field) + self.__norm = numpy.linalg.norm(field.data) self.__conv = self.__norm <= self.__tolerance self.__component_data_view.GetBufferedData().SetValue(self.__field_name.split(':')[0] + "_l2_norm", self.__norm) return self.__conv diff --git a/applications/OptimizationApplication/tests/algorithm_tests/test_convergence.py b/applications/OptimizationApplication/tests/algorithm_tests/test_convergence.py index c840efb7cf3a..72ec8f5da5d0 100644 --- a/applications/OptimizationApplication/tests/algorithm_tests/test_convergence.py +++ b/applications/OptimizationApplication/tests/algorithm_tests/test_convergence.py @@ -60,12 +60,13 @@ def test_L2(self): algorithm_data = ComponentDataView("algorithm", self.optimization_problem) convergence_criterium = l2_conv_criterion.L2ConvCriterion(param, self.optimization_problem) convergence_criterium.Initialize() - search_direction = KratosOA.CollectiveExpression([Kratos.Expression.ElementExpression(self.model_part)]) - KratosOA.CollectiveExpressionIO.Read(search_direction, KratosOA.CollectiveExpressionIO.PropertiesVariable(Kratos.DENSITY)) + search_direction = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(self.model_part.Elements, Kratos.DENSITY)]) + search_direction.CollectData() algorithm_data.GetBufferedData()["search_direction"] = search_direction self.assertFalse(convergence_criterium.IsConverged()) self.optimization_problem.AdvanceStep() - algorithm_data.GetBufferedData()["search_direction"] = search_direction / 100000 + algorithm_data.GetBufferedData()["search_direction"] = search_direction + search_direction.data[:] /= 100000 self.assertTrue(convergence_criterium.IsConverged()) def test_L2_max(self): @@ -87,8 +88,8 @@ def test_L2_max(self): convergence_criterium.Add(convergence_criterium_additional) convergence_criterium.Initialize() - search_direction = KratosOA.CollectiveExpression([Kratos.Expression.ElementExpression(self.model_part)]) - KratosOA.CollectiveExpressionIO.Read(search_direction, KratosOA.CollectiveExpressionIO.PropertiesVariable(Kratos.DENSITY)) + search_direction = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(self.model_part.Elements, Kratos.DENSITY)]) + search_direction.CollectData() algorithm_data.GetBufferedData()["search_direction"] = search_direction self.assertFalse(convergence_criterium.IsConverged()) self.optimization_problem.AdvanceStep() @@ -270,8 +271,8 @@ def test_CombinedConvCriterion(self): convergence_criterion = combined_conv_criterion.CombinedConvCriterion(self.model, params, self.optimization_problem) convergence_criterion.Initialize() - search_direction = KratosOA.CollectiveExpression([Kratos.Expression.ElementExpression(self.model_part)]) - KratosOA.CollectiveExpressionIO.Read(search_direction, KratosOA.CollectiveExpressionIO.PropertiesVariable(Kratos.DENSITY)) + search_direction = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(self.model_part.Elements, Kratos.DENSITY)]) + search_direction.CollectData() algorithm_data.GetBufferedData()["search_direction"] = search_direction algorithm_data.GetBufferedData()["std_obj_value"] = 0.1 @@ -281,11 +282,13 @@ def test_CombinedConvCriterion(self): algorithm_data.GetBufferedData()["std_obj_value"] = 1e-4 self.assertTrue(convergence_criterion.IsConverged()) self.optimization_problem.AdvanceStep() - algorithm_data.GetBufferedData()["search_direction"] = search_direction / 1e+6 + search_direction.data[:] /= 1e+6 + algorithm_data.GetBufferedData()["search_direction"] = search_direction algorithm_data.GetBufferedData()["std_obj_value"] = 0.1 self.assertFalse(convergence_criterion.IsConverged()) self.optimization_problem.AdvanceStep() - algorithm_data.GetBufferedData()["search_direction"] = search_direction / 1e+6 + search_direction.data[:] /= 1e+6 + algorithm_data.GetBufferedData()["search_direction"] = search_direction algorithm_data.GetBufferedData()["std_obj_value"] = 1e-9 self.assertTrue(convergence_criterion.IsConverged()) From 6bf20d1f3bbe8c4aa9f80770394f7acc55f5f156 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 13 Feb 2026 08:21:57 +0100 Subject: [PATCH 080/116] fixing resp util bugs --- ...dd_custom_response_utilities_to_python.cpp | 4 +- .../linear_strain_energy_response_utils.cpp | 43 +++++++++++---- .../linear_strain_energy_response_utils.h | 3 +- .../response/mass_response_utils.cpp | 53 ++++++++++++------- .../response/mass_response_utils.h | 3 +- 5 files changed, 70 insertions(+), 36 deletions(-) diff --git a/applications/OptimizationApplication/custom_python/add_custom_response_utilities_to_python.cpp b/applications/OptimizationApplication/custom_python/add_custom_response_utilities_to_python.cpp index 2091cdfeef36..c7c97cc2f4c4 100644 --- a/applications/OptimizationApplication/custom_python/add_custom_response_utilities_to_python.cpp +++ b/applications/OptimizationApplication/custom_python/add_custom_response_utilities_to_python.cpp @@ -35,12 +35,12 @@ void AddCustomResponseUtilitiesToPython(pybind11::module& m) m.def_submodule("MassResponseUtils") .def("Check", &MassResponseUtils::Check) .def("CalculateValue", &MassResponseUtils::CalculateValue) - .def("CalculateGradient", &MassResponseUtils::CalculateGradient, py::arg("physical_variable"), py::arg("gradient_required_model_parts"), py::arg("gradient_computed_model_parts"), py::arg("combined_tensor_adaptor"), py::arg("perturbation_size")) + .def("CalculateGradient", &MassResponseUtils::CalculateGradient, py::arg("physical_variable"), py::arg("value_influencing_model_part"), py::arg("combined_tensor_adaptor"), py::arg("perturbation_size")) ; m.def_submodule("LinearStrainEnergyResponseUtils") .def("CalculateValue", &LinearStrainEnergyResponseUtils::CalculateValue) - .def("CalculateGradient", &LinearStrainEnergyResponseUtils::CalculateGradient, py::arg("physical_variable"), py::arg("gradient_required_model_parts"), py::arg("gradient_computed_model_parts"), py::arg("combined_tensor_adaptor"), py::arg("perturbation_size")) + .def("CalculateGradient", &LinearStrainEnergyResponseUtils::CalculateGradient, py::arg("physical_variable"), py::arg("value_influencing_model_part"), py::arg("combined_tensor_adaptor"), py::arg("perturbation_size")) ; m.def_submodule("MaxOverhangAngleResponseUtils") diff --git a/applications/OptimizationApplication/custom_utilities/response/linear_strain_energy_response_utils.cpp b/applications/OptimizationApplication/custom_utilities/response/linear_strain_energy_response_utils.cpp index b1566a39f97f..f180ede7a35b 100644 --- a/applications/OptimizationApplication/custom_utilities/response/linear_strain_energy_response_utils.cpp +++ b/applications/OptimizationApplication/custom_utilities/response/linear_strain_energy_response_utils.cpp @@ -83,8 +83,7 @@ double LinearStrainEnergyResponseUtils::CalculateValue(ModelPart& rEvaluatedMode void LinearStrainEnergyResponseUtils::CalculateGradient( const PhysicalFieldVariableTypes& rPhysicalVariable, - ModelPart& rGradientRequiredModelPart, - ModelPart& rGradientComputedModelPart, + ModelPart& rValueInfluencingModelPart, CombinedTensorAdaptor& rCombinedTensorAdaptor, const double PerturbationSize) { @@ -94,17 +93,41 @@ void LinearStrainEnergyResponseUtils::CalculateGradient( std::visit([&](auto pVariable) { if (*pVariable == YOUNG_MODULUS) { - block_for_each(rGradientRequiredModelPart.Elements(), [](auto& rElement) { rElement.GetProperties().SetValue(YOUNG_MODULUS_SENSITIVITY, 0.0); }); - CalculateStrainEnergyLinearlyDependentPropertyGradient(rGradientComputedModelPart, YOUNG_MODULUS, YOUNG_MODULUS_SENSITIVITY); + // clears the existing values because there may be left over vales on the containers in the provided combined tensor adaptors. + for (const auto& p_ta : temp_cta.GetTensorAdaptors()) { + if (!std::holds_alternative(p_ta->GetContainer())) { + KRATOS_ERROR << pVariable->Name() << " sensitivity can be computed only on elemental containers."; + } + block_for_each(*std::get(p_ta->GetContainer()), [](auto& rElement) { rElement.GetProperties().SetValue(YOUNG_MODULUS_SENSITIVITY, 0.0); }); + } + CalculateStrainEnergyLinearlyDependentPropertyGradient(rValueInfluencingModelPart, YOUNG_MODULUS, YOUNG_MODULUS_SENSITIVITY); } else if (*pVariable == THICKNESS) { - block_for_each(rGradientRequiredModelPart.Elements(), [](auto& rElement) { rElement.GetProperties().SetValue(THICKNESS_SENSITIVITY, 0.0); }); - CalculateStrainEnergySemiAnalyticPropertyGradient(rGradientComputedModelPart, PerturbationSize, THICKNESS, THICKNESS_SENSITIVITY); + // clears the existing values because there may be left over vales on the containers in the provided combined tensor adaptors. + for (const auto& p_ta : temp_cta.GetTensorAdaptors()) { + if (!std::holds_alternative(p_ta->GetContainer())) { + KRATOS_ERROR << pVariable->Name() << " sensitivity can be computed only on elemental containers."; + } + block_for_each(*std::get(p_ta->GetContainer()), [](auto& rElement) { rElement.GetProperties().SetValue(THICKNESS_SENSITIVITY, 0.0); }); + } + CalculateStrainEnergySemiAnalyticPropertyGradient(rValueInfluencingModelPart, PerturbationSize, THICKNESS, THICKNESS_SENSITIVITY); } else if (*pVariable == POISSON_RATIO) { - block_for_each(rGradientRequiredModelPart.Elements(), [](auto& rElement) { rElement.GetProperties().SetValue(POISSON_RATIO_SENSITIVITY, 0.0); }); - CalculateStrainEnergySemiAnalyticPropertyGradient(rGradientComputedModelPart, PerturbationSize, POISSON_RATIO, POISSON_RATIO_SENSITIVITY); + // clears the existing values because there may be left over vales on the containers in the provided combined tensor adaptors. + for (const auto& p_ta : temp_cta.GetTensorAdaptors()) { + if (!std::holds_alternative(p_ta->GetContainer())) { + KRATOS_ERROR << pVariable->Name() << " sensitivity can be computed only on elemental containers."; + } + block_for_each(*std::get(p_ta->GetContainer()), [](auto& rElement) { rElement.GetProperties().SetValue(POISSON_RATIO_SENSITIVITY, 0.0); }); + } + CalculateStrainEnergySemiAnalyticPropertyGradient(rValueInfluencingModelPart, PerturbationSize, POISSON_RATIO, POISSON_RATIO_SENSITIVITY); } else if (*pVariable == SHAPE) { - VariableUtils().SetNonHistoricalVariableToZero(SHAPE_SENSITIVITY, rGradientRequiredModelPart.Nodes()); - CalculateStrainEnergySemiAnalyticShapeGradient(rGradientComputedModelPart, PerturbationSize, SHAPE_SENSITIVITY); + // clears the existing values because shape sensitivity is summed from each element on nodes + for (const auto& p_ta : temp_cta.GetTensorAdaptors()) { + if (!std::holds_alternative(p_ta->GetContainer())) { + KRATOS_ERROR << "SHAPE sensitivity can be computed only on nodal containers."; + } + VariableUtils().SetNonHistoricalVariableToZero(SHAPE_SENSITIVITY, *std::get(p_ta->GetContainer())); + } + CalculateStrainEnergySemiAnalyticShapeGradient(rValueInfluencingModelPart, PerturbationSize, SHAPE_SENSITIVITY); } else { KRATOS_ERROR << "Unsupported sensitivity w.r.t. " << pVariable->Name() diff --git a/applications/OptimizationApplication/custom_utilities/response/linear_strain_energy_response_utils.h b/applications/OptimizationApplication/custom_utilities/response/linear_strain_energy_response_utils.h index e5a0ff4e0be5..8ae0d6c9ae51 100644 --- a/applications/OptimizationApplication/custom_utilities/response/linear_strain_energy_response_utils.h +++ b/applications/OptimizationApplication/custom_utilities/response/linear_strain_energy_response_utils.h @@ -50,8 +50,7 @@ class KRATOS_API(OPTIMIZATION_APPLICATION) LinearStrainEnergyResponseUtils static void CalculateGradient( const PhysicalFieldVariableTypes& rPhysicalVariable, - ModelPart& rGradientRequiredModelPart, - ModelPart& rGradientComputedModelPart, + ModelPart& rValueInfluencingModelPart, CombinedTensorAdaptor& rCombinedTensorAdaptor, const double PerturbationSize); diff --git a/applications/OptimizationApplication/custom_utilities/response/mass_response_utils.cpp b/applications/OptimizationApplication/custom_utilities/response/mass_response_utils.cpp index b6a6e33df555..a5101afacbfb 100644 --- a/applications/OptimizationApplication/custom_utilities/response/mass_response_utils.cpp +++ b/applications/OptimizationApplication/custom_utilities/response/mass_response_utils.cpp @@ -118,8 +118,7 @@ double MassResponseUtils::CalculateValue(const ModelPart& rModelPart) void MassResponseUtils::CalculateGradient( const PhysicalFieldVariableTypes& rPhysicalVariable, - ModelPart& rGradientRequiredModelPart, - ModelPart& rGradientComputedModelPart, + ModelPart& rValueInfluencingModelPart, CombinedTensorAdaptor& rCombinedTensorAdaptor, const double PerturbationSize) { @@ -130,29 +129,43 @@ void MassResponseUtils::CalculateGradient( std::visit([&](auto pVariable) { if (*pVariable == DENSITY) { - // clears the existing values - block_for_each(rGradientRequiredModelPart.Elements(), [](auto& rElement) { rElement.GetProperties().SetValue(DENSITY_SENSITIVITY, 0.0); }); - - // computes density sensitivity and store it within each elements' properties - CalculateMassDensityGradient(rGradientComputedModelPart, DENSITY_SENSITIVITY); + // clears the existing values because there may be left over vales on the containers in the provided combined tensor adaptors. + for (const auto& p_ta : temp_cta.GetTensorAdaptors()) { + if (!std::holds_alternative(p_ta->GetContainer())) { + KRATOS_ERROR << pVariable->Name() << " sensitivity can be computed only on elemental containers."; + } + block_for_each(*std::get(p_ta->GetContainer()), [](auto& rElement) { rElement.GetProperties().SetValue(DENSITY_SENSITIVITY, 0.0); }); + } + CalculateMassDensityGradient(rValueInfluencingModelPart, DENSITY_SENSITIVITY); } else if (*pVariable == THICKNESS) { - // clears the existing values - block_for_each(rGradientRequiredModelPart.Elements(), [](auto& rElement) { rElement.GetProperties().SetValue(THICKNESS_SENSITIVITY, 0.0); }); - - // computes density sensitivity and store it within each elements' properties - CalculateMassThicknessGradient(rGradientComputedModelPart, THICKNESS_SENSITIVITY); + // clears the existing values because there may be left over vales on the containers in the provided combined tensor adaptors. + for (const auto& p_ta : temp_cta.GetTensorAdaptors()) { + if (!std::holds_alternative(p_ta->GetContainer())) { + KRATOS_ERROR << pVariable->Name() << " sensitivity can be computed only on elemental containers."; + } + block_for_each(*std::get(p_ta->GetContainer()), [](auto& rElement) { rElement.GetProperties().SetValue(THICKNESS_SENSITIVITY, 0.0); }); + } + CalculateMassThicknessGradient(rValueInfluencingModelPart, THICKNESS_SENSITIVITY); } else if (*pVariable == CROSS_AREA) { - // clears the existing values - block_for_each(rGradientRequiredModelPart.Elements(), [](auto& rElement) { rElement.GetProperties().SetValue(CROSS_AREA_SENSITIVITY, 0.0); }); - - // computes density sensitivity and store it within each elements' properties - CalculateMassCrossAreaGradient(rGradientComputedModelPart, CROSS_AREA_SENSITIVITY); + // clears the existing values because there may be left over vales on the containers in the provided combined tensor adaptors. + for (const auto& p_ta : temp_cta.GetTensorAdaptors()) { + if (!std::holds_alternative(p_ta->GetContainer())) { + KRATOS_ERROR << pVariable->Name() << " sensitivity can be computed only on elemental containers."; + } + block_for_each(*std::get(p_ta->GetContainer()), [](auto& rElement) { rElement.GetProperties().SetValue(CROSS_AREA_SENSITIVITY, 0.0); }); + } + CalculateMassCrossAreaGradient(rValueInfluencingModelPart, CROSS_AREA_SENSITIVITY); } else if (*pVariable == SHAPE) { - // clears the existing values - VariableUtils().SetNonHistoricalVariableToZero(SHAPE_SENSITIVITY, rGradientRequiredModelPart.Nodes()); + // clears the existing values because shape sensitivity is summed from each element on nodes + for (const auto& p_ta : temp_cta.GetTensorAdaptors()) { + if (!std::holds_alternative(p_ta->GetContainer())) { + KRATOS_ERROR << "SHAPE sensitivity can be computed only on nodal containers."; + } + VariableUtils().SetNonHistoricalVariableToZero(SHAPE_SENSITIVITY, *std::get(p_ta->GetContainer())); + } // computes density sensitivity and store it within each elements' properties - CalculateMassShapeGradient(rGradientComputedModelPart, SHAPE_SENSITIVITY, PerturbationSize); + CalculateMassShapeGradient(rValueInfluencingModelPart, SHAPE_SENSITIVITY, PerturbationSize); } else { KRATOS_ERROR << "Unsupported sensitivity w.r.t. " << pVariable->Name() diff --git a/applications/OptimizationApplication/custom_utilities/response/mass_response_utils.h b/applications/OptimizationApplication/custom_utilities/response/mass_response_utils.h index 9866a12a6845..3fe45fb00b48 100644 --- a/applications/OptimizationApplication/custom_utilities/response/mass_response_utils.h +++ b/applications/OptimizationApplication/custom_utilities/response/mass_response_utils.h @@ -52,8 +52,7 @@ class KRATOS_API(OPTIMIZATION_APPLICATION) MassResponseUtils static void CalculateGradient( const PhysicalFieldVariableTypes& rPhysicalVariable, - ModelPart& rGradientRequiredModelPart, - ModelPart& rGradientComputedModelPart, + ModelPart& rValueInfluencingModelPart, CombinedTensorAdaptor& rCombinedTensorAdaptor, const double PerturbationSize); From 095eadd413239864ebe2f4953ddb4f98e04b38e4 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 13 Feb 2026 08:22:24 +0100 Subject: [PATCH 081/116] update linear and mass resps --- .../responses/linear_strain_energy_response_function.py | 1 - .../python_scripts/responses/mass_response_function.py | 2 -- 2 files changed, 3 deletions(-) diff --git a/applications/OptimizationApplication/python_scripts/responses/linear_strain_energy_response_function.py b/applications/OptimizationApplication/python_scripts/responses/linear_strain_energy_response_function.py index 28e8a574f350..890a2f4cda9c 100644 --- a/applications/OptimizationApplication/python_scripts/responses/linear_strain_energy_response_function.py +++ b/applications/OptimizationApplication/python_scripts/responses/linear_strain_energy_response_function.py @@ -65,7 +65,6 @@ def CalculateGradient(self, physical_variable_combined_tensor_adaptor: 'dict[Sup KratosOA.ResponseUtils.LinearStrainEnergyResponseUtils.CalculateGradient( physical_variable, self.GetInfluencingModelPart(), - self.GetInfluencingModelPart(), cta, self.perturbation_size) diff --git a/applications/OptimizationApplication/python_scripts/responses/mass_response_function.py b/applications/OptimizationApplication/python_scripts/responses/mass_response_function.py index 1b8eecfca726..9260b71a8fce 100644 --- a/applications/OptimizationApplication/python_scripts/responses/mass_response_function.py +++ b/applications/OptimizationApplication/python_scripts/responses/mass_response_function.py @@ -4,7 +4,6 @@ import KratosMultiphysics.OptimizationApplication as KratosOA from KratosMultiphysics.OptimizationApplication.responses.response_function import ResponseFunction from KratosMultiphysics.OptimizationApplication.responses.response_function import SupportedSensitivityFieldVariableTypes -from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes from KratosMultiphysics.OptimizationApplication.utilities.model_part_utilities import ModelPartOperation def Factory(model: Kratos.Model, parameters: Kratos.Parameters, _) -> ResponseFunction: @@ -65,7 +64,6 @@ def CalculateGradient(self, physical_variable_combined_tensor_adaptor: 'dict[Sup KratosOA.ResponseUtils.MassResponseUtils.CalculateGradient( physical_variable, self.model_part, - self.model_part, cta, self.perturbation_size) From d499be4bcc7efd10d45c92a3b15606b72566f2f9 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 13 Feb 2026 08:23:03 +0100 Subject: [PATCH 082/116] update combined resp func --- .../responses/combined_response_function.py | 37 +++++++++---------- .../test_combined_response_function.py | 26 ++++++------- 2 files changed, 30 insertions(+), 33 deletions(-) diff --git a/applications/OptimizationApplication/python_scripts/responses/combined_response_function.py b/applications/OptimizationApplication/python_scripts/responses/combined_response_function.py index 395afc55ebc3..5c14ae9473d7 100644 --- a/applications/OptimizationApplication/python_scripts/responses/combined_response_function.py +++ b/applications/OptimizationApplication/python_scripts/responses/combined_response_function.py @@ -1,7 +1,6 @@ from typing import Optional import KratosMultiphysics as Kratos -import KratosMultiphysics.OptimizationApplication as KratosOA from KratosMultiphysics.OptimizationApplication.responses.response_function import ResponseFunction from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes from KratosMultiphysics.OptimizationApplication.utilities.model_part_utilities import ModelPartOperation @@ -100,31 +99,29 @@ def CalculateValue(self) -> float: raise RuntimeError(f"Unsupported combining_method = \"{self.combining_method}\". Followings are supported:\n\tsum") return value - def CalculateGradient(self, physical_variable_collective_expressions: 'dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]') -> None: + def CalculateGradient(self, physical_variable_combined_tensor_adaptor: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]') -> None: # make everything zeros - for physical_variable, collective_expression in physical_variable_collective_expressions.items(): - for container_expression in collective_expression.GetContainerExpressions(): - Kratos.Expression.LiteralExpressionIO.SetDataToZero(container_expression, physical_variable) + for _, combined_tensor_adaptor in physical_variable_combined_tensor_adaptor.items(): + combined_tensor_adaptor.data[:] = 0.0 + Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(combined_tensor_adaptor, perform_store_data_recursively=False, copy=False).StoreData() for response_function, weight in self.list_of_responses: # get the map for the response function - sub_physical_variable_collective_expressions: 'dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]' = {} - for physical_variable, collective_expression in physical_variable_collective_expressions.items(): + sub_physical_variable_combined_tensor_adaptor: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]' = {} + for physical_variable, combined_tensor_adaptor in physical_variable_combined_tensor_adaptor.items(): if physical_variable in response_function.GetImplementedPhysicalKratosVariables(): - sub_physical_variable_collective_expressions[physical_variable] = collective_expression.Clone() + sub_physical_variable_combined_tensor_adaptor[physical_variable] = combined_tensor_adaptor.Clone() # calculate the gradients - response_function.CalculateGradient(sub_physical_variable_collective_expressions) + response_function.CalculateGradient(sub_physical_variable_combined_tensor_adaptor) # now aggregate the gradients - for physical_variable, local_collective_expression in sub_physical_variable_collective_expressions.items(): - self.unbuffered_data.SetValue(f"d{response_function.GetName()}_d{physical_variable.Name()}", local_collective_expression, overwrite=True) - combined_collective_expression = physical_variable_collective_expressions[physical_variable] - for i, local_container_expression in enumerate(local_collective_expression.GetContainerExpressions()): - local_exp = local_container_expression - combined_container_exp = combined_collective_expression.GetContainerExpressions()[i] - - if self.combining_method == "sum": - combined_container_exp.SetExpression(Kratos.Expression.Utils.Collapse(combined_container_exp + local_exp * weight).GetExpression()) - else: - raise RuntimeError(f"Unsupported combining_method = \"{self.combining_method}\". Followings are supported:\n\tsum") + for physical_variable, local_combined_tensor_adaptor in sub_physical_variable_combined_tensor_adaptor.items(): + self.unbuffered_data.SetValue(f"d{response_function.GetName()}_d{physical_variable.Name()}", local_combined_tensor_adaptor.Clone(), overwrite=True) + if self.combining_method == "sum": + physical_variable_combined_tensor_adaptor[physical_variable].data[:] += local_combined_tensor_adaptor.data[:] * weight + else: + raise RuntimeError(f"Unsupported combining_method = \"{self.combining_method}\". Followings are supported:\n\tsum") + + for _, combined_tensor_adaptor in physical_variable_combined_tensor_adaptor.items(): + Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(combined_tensor_adaptor, perform_store_data_recursively=False, copy=False).StoreData() \ No newline at end of file diff --git a/applications/OptimizationApplication/tests/responses_tests/test_combined_response_function.py b/applications/OptimizationApplication/tests/responses_tests/test_combined_response_function.py index 9af9cb375fc0..41fb8f56ac4c 100644 --- a/applications/OptimizationApplication/tests/responses_tests/test_combined_response_function.py +++ b/applications/OptimizationApplication/tests/responses_tests/test_combined_response_function.py @@ -1,3 +1,4 @@ +import numpy import KratosMultiphysics as Kratos import KratosMultiphysics.OptimizationApplication as KratosOA import KratosMultiphysics.KratosUnittest as kratos_unittest @@ -132,18 +133,18 @@ def test_CalculateValue(self): def test_CalculateGradient(self): def get_data(add_density_physical_var = True): - elem_exp = Kratos.Expression.ElementExpression(self.model_part) - nodal_exp = Kratos.Expression.NodalExpression(self.model_part) + elem_ta = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Elements, Kratos.DENSITY) + nodal_ta = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, KratosOA.SHAPE) if add_density_physical_var: data = { - Kratos.DENSITY: KratosOA.CollectiveExpression([elem_exp]), - KratosOA.SHAPE: KratosOA.CollectiveExpression([nodal_exp]) + Kratos.DENSITY: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([elem_ta], copy=False), + KratosOA.SHAPE: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([nodal_ta], copy=False) } else: data = { - KratosOA.SHAPE: KratosOA.CollectiveExpression([nodal_exp]) + KratosOA.SHAPE: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([nodal_ta], copy=False) } - return nodal_exp, elem_exp, data + return nodal_ta, elem_ta, data # calculate all the values first self.resp_8.CalculateValue() @@ -164,18 +165,17 @@ def get_data(add_density_physical_var = True): v7_shape, v7_rho, data = get_data() self.resp_7.CalculateGradient(data) - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(v6_shape - v1_shape * 2.1 - v2_shape * 3.1 - v3_shape * 4.1), 0.0) - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(v6_rho - v1_rho * 2.1 - v2_rho * 3.1 - v3_rho * 4.1), 0.0) + self.assertVectorAlmostEqual(v6_shape.data.ravel(), (v1_shape.data[:] * 2.1 + v2_shape.data[:] * 3.1 + v3_shape.data[:] * 4.1).ravel()) + self.assertVectorAlmostEqual(v6_rho.data.ravel(), (v1_rho.data * 2.1 + v2_rho.data * 3.1 + v3_rho.data * 4.1).ravel()) - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(v7_shape - v4_shape * 5.1 - v5_shape * 6.1), 0.0) - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(v7_rho - v4_rho * 5.1), 0.0) + self.assertVectorAlmostEqual(v7_shape.data.ravel(), (v4_shape.data * 5.1 + v5_shape.data * 6.1).ravel()) + self.assertVectorAlmostEqual(v7_rho.data.ravel(), (v4_rho.data * 5.1).ravel()) v8_shape, v8_rho, data = get_data() self.resp_8.CalculateGradient(data) - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(v8_shape - v6_shape * 7.1 - v7_shape * 8.1), 0.0) - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(v8_rho - v6_rho * 7.1 - v7_rho * 8.1), 0.0) + self.assertVectorAlmostEqual(v8_shape.data.ravel(), (v6_shape.data * 7.1 + v7_shape.data * 8.1).ravel()) + self.assertVectorAlmostEqual(v8_rho.data.ravel(), (v6_rho.data * 7.1 + v7_rho.data * 8.1).ravel()) if __name__ == "__main__": - Kratos.Tester.SetVerbosity(Kratos.Tester.Verbosity.PROGRESS) # TESTS_OUTPUTS kratos_unittest.main() \ No newline at end of file From 25fe9db558234296a6b1bc72cc844e2289487b36 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 13 Feb 2026 11:49:25 +0100 Subject: [PATCH 083/116] update vtu output to ta --- ...optimization_problem_vtu_output_process.py | 210 +++++++++-------- .../tests/process_tests/test_1_orig.vtu | 213 +++++++++--------- .../tests/process_tests/test_2_orig.vtu | 117 +++++----- ...optimization_problem_vtu_output_process.py | 60 +++-- 4 files changed, 307 insertions(+), 293 deletions(-) diff --git a/applications/OptimizationApplication/python_scripts/processes/optimization_problem_vtu_output_process.py b/applications/OptimizationApplication/python_scripts/processes/optimization_problem_vtu_output_process.py index 60c89154b3c7..af836c71ce35 100644 --- a/applications/OptimizationApplication/python_scripts/processes/optimization_problem_vtu_output_process.py +++ b/applications/OptimizationApplication/python_scripts/processes/optimization_problem_vtu_output_process.py @@ -1,10 +1,8 @@ from typing import Any, Union -from abc import ABC, abstractmethod from pathlib import Path import KratosMultiphysics as Kratos import KratosMultiphysics.kratos_utilities as kratos_utils -import KratosMultiphysics.OptimizationApplication as KratosOA from KratosMultiphysics.OptimizationApplication.responses.response_function import ResponseFunction from KratosMultiphysics.OptimizationApplication.controls.control import Control from KratosMultiphysics.OptimizationApplication.execution_policies.execution_policy import ExecutionPolicy @@ -12,67 +10,60 @@ from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem_utilities import GetAllComponentFullNamesWithData from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem_utilities import GetComponentHavingDataByFullName -from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import ContainerExpressionTypes -def Factory(_: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem) -> Any: +def Factory(model: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem) -> Any: if not parameters.Has("settings"): raise RuntimeError(f"OptimizationProblemVtuOutputProcess instantiation requires a \"settings\" in parameters [ parameters = {parameters}].") - return OptimizationProblemVtuOutputProcess(parameters["settings"], optimization_problem) + return OptimizationProblemVtuOutputProcess(model, parameters["settings"], optimization_problem) -class ExpressionData(ABC): - def __init__(self, expression_path: str, container_expression: ContainerExpressionTypes) -> None: - self.expression_path = expression_path - self.container_expression_type = type(container_expression) - self.model_part = container_expression.GetModelPart() +class TensorAdaptorData: + def __init__(self, tensor_adaptor_path: str, tensor_adaptor: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> None: + self.tensor_adaptor_path = tensor_adaptor_path + self.container = tensor_adaptor.GetContainer() - def GetContainerExpressionType(self) -> Any: - return self.container_expression_type + def GetTensorAdaptorName(self) -> str: + return self.tensor_adaptor_path[self.tensor_adaptor_path.rfind("/")+1:] - def GetContainerExpressionName(self) -> str: - return self.expression_path[self.expression_path.rfind("/")+1:] + def GetTensorAdaptorPath(self) -> str: + return self.tensor_adaptor_path - def GetExpressionPath(self) -> str: - return self.expression_path + def GetContainer(self): + return self.container - def GetModelPart(self) -> Kratos.ModelPart: - return self.model_part + def GetTensorAdaptor(self, optimization_problem: OptimizationProblem) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + data = optimization_problem.GetProblemDataContainer()[self.tensor_adaptor_path] - def _IsValidContainerExpression(self, container_expression: ContainerExpressionTypes) -> bool: - return isinstance(container_expression, self.container_expression_type) and self.model_part == container_expression.GetModelPart() + if not isinstance(data, Kratos.TensorAdaptors.DoubleTensorAdaptor): + raise RuntimeError(f"The data type at \"{self.tensor_adaptor_path}\" changed from {Kratos.TensorAdaptors.DoubleTensorAdaptor.__name__} to {type(data).__class__.__name__}. Found data = {data}") + if not data.HasContainer(): + raise RuntimeError(f"The data at \"{self.tensor_adaptor_path}\" does not represent a {Kratos.TensorAdaptors.DoubleTensorAdaptor.__name__} with a container. Found data = {data}") + if data.GetContainer() != self.container: + raise RuntimeError(f"The container at \"{self.tensor_adaptor_path}\" mismatch with the original container. Found data = {data}") - @abstractmethod - def GetContainerExpression(self, optiization_problem: OptimizationProblem) -> ContainerExpressionTypes: - pass + return data -class ContainerExpressionData(ExpressionData): - def __inif__(self, expression_path: str, container_expression: ContainerExpressionTypes): - super().__init__(expression_path, container_expression) +class CombinedTensorAdaptorData(TensorAdaptorData): + def __init__(self, combined_tensor_adaptor_path: str, combined_tensor_adaptor: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor, tensor_adaptor_index: int) -> None: + super().__init__(combined_tensor_adaptor_path, combined_tensor_adaptor.GetTensorAdaptors()[tensor_adaptor_index]) + self.tensor_adaptor_index = tensor_adaptor_index - def GetContainerExpression(self, optiization_problem: OptimizationProblem) -> ContainerExpressionTypes: - data = optiization_problem.GetProblemDataContainer()[self.expression_path] - if not self._IsValidContainerExpression(data): - raise RuntimeError(f"The data at \"{self.expression_path}\" is not valid. The original data found at this location is of type {self.container_expression_type.__name__} with {self.model_part.FullName()}. Found data = {data}") - return data + def GetTensorAdaptor(self, optimization_problem: OptimizationProblem) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + data = optimization_problem.GetProblemDataContainer()[self.tensor_adaptor_path] -class CollectiveExpressionData(ExpressionData): - def __init__(self, collective_expression_path: str, collective_expression: KratosOA.CollectiveExpression, container_expression_index: int): - super().__init__(collective_expression_path, collective_expression.GetContainerExpressions()[container_expression_index]) - self.container_expression_index = container_expression_index - - def GetContainerExpression(self, optiization_problem: OptimizationProblem) -> ContainerExpressionTypes: - data = optiization_problem.GetProblemDataContainer()[self.expression_path] - if not isinstance(data, KratosOA.CollectiveExpression): - raise RuntimeError(f"The data type at \"{self.expression_path}\" changed from {KratosOA.CollectiveExpression.__name__} to {type(data).__class__.__name__}.") - data = data.GetContainerExpressions()[self.container_expression_index] - if not self._IsValidContainerExpression(data): - raise RuntimeError(f"The data at \"{self.expression_path}\" is not valid. The original data found at this location is of type {self.container_expression_type.__name__} with {self.model_part.FullName()}. Found data = {data}") - return data + if not isinstance(data, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor): + raise RuntimeError(f"The data type at \"{self.tensor_adaptor_path}\" changed from {Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor.__name__} to {type(data).__class__.__name__}. Found data = {data}") + if not data.GetTensorAdaptors()[self.tensor_adaptor_index].HasContainer(): + raise RuntimeError(f"The tensor adaptor at \"{self.tensor_adaptor_path}\" with index = {self.tensor_adaptor_index} does not represent a {Kratos.TensorAdaptors.DoubleTensorAdaptor.__name__} with a container. Found data = {data}") + if data.GetTensorAdaptors()[self.tensor_adaptor_index].GetContainer() != self.container: + raise RuntimeError(f"The container from tensor adaptor \"{self.tensor_adaptor_path}\" with index = {self.tensor_adaptor_index} mismatch with the original container. Found data = {data}") -class ExpressionVtuOutput: + return data.GetTensorAdaptors()[self.tensor_adaptor_index] + +class TensorAdaptorVtuOutput: def __init__(self, parameters: 'dict[str, Any]', model_part: Kratos.ModelPart, optimization_problem: OptimizationProblem): self.model_part = model_part self.optimization_problem = optimization_problem - self.output_file_name_prefix = parameters["output_file_name_prefix"] + self.output_file_name_prefix: str = parameters["output_file_name_prefix"] if parameters["save_output_files_in_folder"]: self.output_path = Path(parameters["output_path"]) @@ -84,58 +75,34 @@ def __init__(self, parameters: 'dict[str, Any]', model_part: Kratos.ModelPart, o else: self.output_path = Path(".") - self.vtu_output: Kratos.VtuOutput = Kratos.VtuOutput(model_part, parameters["is_initial_configuration"], parameters["writer_format"], parameters["precision"]) - self.dict_of_expression_data: 'dict[Any, dict[str, ExpressionData]]' = {} - - # vtu output gives priority to elements over conditions if both are present. - # nodal container expression is allowed in any case. hence that is added first - self.dict_of_expression_data[Kratos.Expression.NodalExpression] = {} - - # now check for elements - communicator: Kratos.Communicator = self.model_part.GetCommunicator() - if communicator.GlobalNumberOfElements() > 0: - self.dict_of_expression_data[Kratos.Expression.ElementExpression] = {} - elif communicator.GlobalNumberOfConditions() > 0: - self.dict_of_expression_data[Kratos.Expression.ConditionExpression] = {} - - def AddExpressionData(self, expression_data: ExpressionData) -> bool: - if expression_data.GetModelPart() == self.vtu_output.GetModelPart(): - current_expression_type = expression_data.GetContainerExpressionType() - if current_expression_type not in self.dict_of_expression_data.keys(): - raise RuntimeError(f"The {current_expression_type.__name__} is not supported to be written in vtu format for {self.model_part.FullName()}") - - dict_of_current_expression_type = self.dict_of_expression_data[current_expression_type] - - current_expression_name = expression_data.GetContainerExpressionName() - if current_expression_name not in dict_of_current_expression_type.keys(): - dict_of_current_expression_type[current_expression_name] = expression_data - else: - raise RuntimeError(f"Trying to add a duplicate expression with the name = \"{current_expression_name}\" [ The original data path = \"{dict_of_current_expression_type[current_expression_name].GetExpressionPath()}\", current data path = \"{expression_data.GetExpressionPath()}\"].") + self.vtu_output: Kratos.Future.VtuOutput = Kratos.Future.VtuOutput(model_part, parameters["configuration"], parameters["writer_format"], parameters["precision"], output_sub_model_parts=True, echo_level=parameters["echo_level"], write_ids=parameters["write_ids"]) + self.list_of_tensor_adaptor_data: 'list[TensorAdaptorData]' = [] + def AddTensorAdaptorData(self, tensor_adaptor_data: TensorAdaptorData) -> bool: + if tensor_adaptor_data.GetContainer() in self.vtu_output.GetOutputContainerList(): + self.list_of_tensor_adaptor_data.append(tensor_adaptor_data) return True - return False def WriteOutput(self): - for current_expression_name_data_pair in self.dict_of_expression_data.values(): - for expression_data in current_expression_name_data_pair.values(): - self.vtu_output.AddContainerExpression(expression_data.GetContainerExpressionName(), expression_data.GetContainerExpression(self.optimization_problem)) + for tensor_adaptor_data in self.list_of_tensor_adaptor_data: + self.vtu_output.EmplaceTensorAdaptor(tensor_adaptor_data.GetTensorAdaptorName(), tensor_adaptor_data.GetTensorAdaptor(self.optimization_problem)) output_file_name = self.output_file_name_prefix output_file_name = output_file_name.replace("", self.model_part.FullName()) output_file_name = output_file_name.replace("", self.model_part.Name) - output_file_name = output_file_name.replace("", str(self.optimization_problem.GetStep())) - self.vtu_output.PrintOutput(str(self.output_path /output_file_name)) + self.vtu_output.PrintOutput(str(self.output_path / output_file_name)) class OptimizationProblemVtuOutputProcess(Kratos.OutputProcess): def GetDefaultParameters(self): return Kratos.Parameters( """ { - "file_name" : "_", + "file_name" : "", "file_format" : "binary", "output_path" : "Optimization_Results", "save_output_files_in_folder" : true, + "write_ids" : false, "write_deformed_configuration": false, "list_of_output_components" : ["all"], "output_precision" : 7, @@ -145,29 +112,39 @@ def GetDefaultParameters(self): """ ) - def __init__(self, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem) -> None: + def __init__(self, model: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem) -> None: super().__init__() parameters.ValidateAndAssignDefaults(self.GetDefaultParameters()) + self.model = model self.optimization_problem = optimization_problem self.echo_level = parameters["echo_level"].GetInt() self.file_name = parameters["file_name"].GetString() self.output_path = parameters["output_path"].GetString() self.save_output_files_in_folder = parameters["save_output_files_in_folder"].GetBool() - self.write_deformed_configuration = parameters["write_deformed_configuration"].GetBool() self.output_precision = parameters["output_precision"].GetInt() + self.write_ids = parameters["write_ids"].GetBool() file_format = parameters["file_format"].GetString() if file_format == "ascii": - self.writer_format = Kratos.VtuOutput.ASCII + self.writer_format = Kratos.Future.VtuOutput.ASCII elif file_format == "binary": - self.writer_format = Kratos.VtuOutput.BINARY + self.writer_format = Kratos.Future.VtuOutput.BINARY + elif file_format == "raw": + self.writer_format = Kratos.Future.VtuOutput.RAW + elif file_format == "compressed_raw": + self.writer_format = Kratos.Future.VtuOutput.COMPRESSED_RAW + else: + raise RuntimeError(f"Only supports \"ascii\", \"binary\", \"raw\", and \"compressed_raw\" file_format. [ provided file_format = \"{file_format}\" ].") + + if parameters["write_deformed_configuration"].GetBool(): + self.configuration = Kratos.Configuration.Current else: - raise RuntimeError(f"Only supports \"ascii\" and \"binary\" file_format. [ provided file_format = \"{file_format}\" ].") + self.configuration = Kratos.Configuration.Initial self.list_of_component_names = parameters["list_of_output_components"].GetStringArray() - self.list_of_expresson_vtu_outputs: 'list[ExpressionVtuOutput]' = [] + self.list_of_tensor_adaptor_vtu_outputs: 'list[TensorAdaptorVtuOutput]' = [] self.initialized_vtu_outputs = False def PrintOutput(self) -> None: @@ -175,8 +152,8 @@ def PrintOutput(self) -> None: self.InitializeVtuOutputIO() self.initialized_vtu_outputs = True - for expression_vtu_output in self.list_of_expresson_vtu_outputs: - expression_vtu_output.WriteOutput() + for tensor_adaptor_vtu_output in self.list_of_tensor_adaptor_vtu_outputs: + tensor_adaptor_vtu_output.WriteOutput() def InitializeVtuOutputIO(self) -> None: # get all the component names at the first writing point @@ -197,35 +174,56 @@ def InitializeVtuOutputIO(self) -> None: found_valid_component = True break - # if a valid component is found, add the expression + # if a valid component is found, add the tensor adaptor if found_valid_component: - if isinstance(global_v, Kratos.Expression.NodalExpression) or \ - isinstance(global_v, Kratos.Expression.ConditionExpression) or \ - isinstance(global_v, Kratos.Expression.ElementExpression): - self._AddContainerExpression(ContainerExpressionData(global_k, global_v)) - elif isinstance(global_v, KratosOA.CollectiveExpression): - for i, _ in enumerate(global_v.GetContainerExpressions()): - self._AddContainerExpression(CollectiveExpressionData(global_k, global_v, i)) - - def _AddContainerExpression(self, expression_data: ExpressionData): + if isinstance(global_v, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor): + for i, _ in enumerate(global_v.GetTensorAdaptors()): + self._AddContainerTensorAdaptor(CombinedTensorAdaptorData(global_k, global_v, i)) + elif isinstance(global_v, Kratos.TensorAdaptors.DoubleTensorAdaptor) or \ + isinstance(global_v, Kratos.TensorAdaptors.IntTensorAdaptor) or \ + isinstance(global_v, Kratos.TensorAdaptors.BoolTensorAdaptor): + self._AddContainerTensorAdaptor(TensorAdaptorData(global_k, global_v)) + + def _AddContainerTensorAdaptor(self, tensor_adaptor_data: TensorAdaptorData): found_vtu_output = False - for expression_vtu_output in self.list_of_expresson_vtu_outputs: - if expression_vtu_output.AddExpressionData(expression_data): + for tensor_adaptor_vtu_output in self.list_of_tensor_adaptor_vtu_outputs: + if tensor_adaptor_vtu_output.AddTensorAdaptorData(tensor_adaptor_data): found_vtu_output = True break if not found_vtu_output: vtu_parameters = { "output_file_name_prefix": self.file_name, - "is_initial_configuration": not self.write_deformed_configuration, + "configuration": self.configuration, "writer_format": self.writer_format, "precision": self.output_precision, "save_output_files_in_folder": self.save_output_files_in_folder, - "output_path": self.output_path + "output_path": self.output_path, + "echo_level": self.echo_level, + "write_ids": self.write_ids } - expression_vtu_output = ExpressionVtuOutput(vtu_parameters, expression_data.GetModelPart(), self.optimization_problem) - expression_vtu_output.AddExpressionData(expression_data) - self.list_of_expresson_vtu_outputs.append(expression_vtu_output) + tensor_adaptor_vtu_output = TensorAdaptorVtuOutput(vtu_parameters, self.__GetRootModelPart(tensor_adaptor_data.GetContainer()), self.optimization_problem) + tensor_adaptor_vtu_output.AddTensorAdaptorData(tensor_adaptor_data) + self.list_of_tensor_adaptor_vtu_outputs.append(tensor_adaptor_vtu_output) if self.echo_level > 0: - Kratos.Logger.PrintInfo(self.__class__.__name__, f"Created expression vtu output for {expression_data.GetModelPart().FullName()}.") \ No newline at end of file + Kratos.Logger.PrintInfo(self.__class__.__name__, f"Created tensor adaptor vtu output for {tensor_adaptor_vtu_output.vtu_output.GetModelPart().FullName()}.") + + def __GetRootModelPart(self, container) -> Kratos.ModelPart: + def get_model_part(container, model_part: Kratos.ModelPart): + if container in [model_part.Nodes, model_part.Conditions, model_part.Elements]: + return model_part.GetRootModelPart() + + for sub_model_part_name in model_part.GetSubModelPartNames(): + root_model_part = get_model_part(container, model_part.GetSubModelPart(sub_model_part_name)) + if root_model_part is not None: + return root_model_part + + return None + + for model_part_name in self.model.GetModelPartNames(): + root_model_part = get_model_part(container, self.model[model_part_name]) + if root_model_part is not None: + return root_model_part + + raise RuntimeError(f"No model part contains the provided container.") \ No newline at end of file diff --git a/applications/OptimizationApplication/tests/process_tests/test_1_orig.vtu b/applications/OptimizationApplication/tests/process_tests/test_1_orig.vtu index 506dcb4233f2..7468f9c6e082 100644 --- a/applications/OptimizationApplication/tests/process_tests/test_1_orig.vtu +++ b/applications/OptimizationApplication/tests/process_tests/test_1_orig.vtu @@ -1,168 +1,169 @@ - + + - + - - SAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPA/AAAAAAAA8D8AAAAAAAAAAA== + + 0.0000000e+00 0.0000000e+00 0.0000000e+00 1.0000000e+00 0.0000000e+00 0.0000000e+00 1.0000000e+00 1.0000000e+00 0.0000000e+00 - - DAAAAAAAAAABAAAAAgAAAA== + + 0 1 2 - - BAAAAAMAAAA= + + 3 - - AQAAAAU= + + 5 - - SAAAAGZmZmZmZiJAmZmZmZmZK0BmZmZmZmYyQJmZmZmZmStAZmZmZmZmMkAAAAAAAAA3QGZmZmZmZjJAAAAAAAAAN0CZmZmZmZk7QA== + + 9.2000000e+00 1.3800000e+01 1.8400000e+01 1.3800000e+01 1.8400000e+01 2.3000000e+01 1.8400000e+01 2.3000000e+01 2.7600000e+01 - - SAAAAAAAAAAAAFdAAAAAAABAYUAAAAAAAABnQAAAAAAAQGFAAAAAAAAAZ0D//////79sQAAAAAAAAGdA//////+/bEAAAAAAAEBxQA== + + 9.2000000e+01 1.3800000e+02 1.8400000e+02 1.3800000e+02 1.8400000e+02 2.3000000e+02 1.8400000e+02 2.3000000e+02 2.7600000e+02 - - SAAAAGZmZmZmZhJAmZmZmZmZG0BmZmZmZmYiQJmZmZmZmRtAZmZmZmZmIkAAAAAAAAAnQGZmZmZmZiJAAAAAAAAAJ0CZmZmZmZkrQA== + + 4.6000000e+00 6.9000000e+00 9.2000000e+00 6.9000000e+00 9.2000000e+00 1.1500000e+01 9.2000000e+00 1.1500000e+01 1.3800000e+01 - - SAAAAAAAAAAAAEdAAAAAAABAUUAAAAAAAABXQAAAAAAAQFFAAAAAAAAAV0D//////79cQAAAAAAAAFdA//////+/XEAAAAAAAEBhQA== + + 4.6000000e+01 6.9000000e+01 9.2000000e+01 6.9000000e+01 9.2000000e+01 1.1500000e+02 9.2000000e+01 1.1500000e+02 1.3800000e+02 - - SAAAAGZmZmZmZiJAmZmZmZmZK0BmZmZmZmYyQJmZmZmZmStAZmZmZmZmMkAAAAAAAAA3QGZmZmZmZjJAAAAAAAAAN0CZmZmZmZk7QA== + + 9.2000000e+00 1.3800000e+01 1.8400000e+01 1.3800000e+01 1.8400000e+01 2.3000000e+01 1.8400000e+01 2.3000000e+01 2.7600000e+01 - - SAAAAAAAAAAAAFdAAAAAAABAYUAAAAAAAABnQAAAAAAAQGFAAAAAAAAAZ0D//////79sQAAAAAAAAGdA//////+/bEAAAAAAAEBxQA== + + 9.2000000e+01 1.3800000e+02 1.8400000e+02 1.3800000e+02 1.8400000e+02 2.3000000e+02 1.8400000e+02 2.3000000e+02 2.7600000e+02 - - SAAAAGZmZmZmZhJAmZmZmZmZG0BmZmZmZmYiQJmZmZmZmRtAZmZmZmZmIkAAAAAAAAAnQGZmZmZmZiJAAAAAAAAAJ0CZmZmZmZkrQA== + + 4.6000000e+00 6.9000000e+00 9.2000000e+00 6.9000000e+00 9.2000000e+00 1.1500000e+01 9.2000000e+00 1.1500000e+01 1.3800000e+01 - - SAAAAAAAAAAAAEdAAAAAAABAUUAAAAAAAABXQAAAAAAAQFFAAAAAAAAAV0D//////79cQAAAAAAAAFdA//////+/XEAAAAAAAEBhQA== + + 4.6000000e+01 6.9000000e+01 9.2000000e+01 6.9000000e+01 9.2000000e+01 1.1500000e+02 9.2000000e+01 1.1500000e+02 1.3800000e+02 - - SAAAAGZmZmZmZiJAmZmZmZmZK0BmZmZmZmYyQJmZmZmZmStAZmZmZmZmMkAAAAAAAAA3QGZmZmZmZjJAAAAAAAAAN0CZmZmZmZk7QA== + + 9.2000000e+00 1.3800000e+01 1.8400000e+01 1.3800000e+01 1.8400000e+01 2.3000000e+01 1.8400000e+01 2.3000000e+01 2.7600000e+01 - - SAAAAAAAAAAAAFdAAAAAAABAYUAAAAAAAABnQAAAAAAAQGFAAAAAAAAAZ0D//////79sQAAAAAAAAGdA//////+/bEAAAAAAAEBxQA== + + 9.2000000e+01 1.3800000e+02 1.8400000e+02 1.3800000e+02 1.8400000e+02 2.3000000e+02 1.8400000e+02 2.3000000e+02 2.7600000e+02 - - SAAAAGZmZmZmZhJAmZmZmZmZG0BmZmZmZmYiQJmZmZmZmRtAZmZmZmZmIkAAAAAAAAAnQGZmZmZmZiJAAAAAAAAAJ0CZmZmZmZkrQA== + + 4.6000000e+00 6.9000000e+00 9.2000000e+00 6.9000000e+00 9.2000000e+00 1.1500000e+01 9.2000000e+00 1.1500000e+01 1.3800000e+01 - - SAAAAAAAAAAAAEdAAAAAAABAUUAAAAAAAABXQAAAAAAAQFFAAAAAAAAAV0D//////79cQAAAAAAAAFdA//////+/XEAAAAAAAEBhQA== + + 4.6000000e+01 6.9000000e+01 9.2000000e+01 6.9000000e+01 9.2000000e+01 1.1500000e+02 9.2000000e+01 1.1500000e+02 1.3800000e+02 - - SAAAAGZmZmZmZiJAmZmZmZmZK0BmZmZmZmYyQJmZmZmZmStAZmZmZmZmMkAAAAAAAAA3QGZmZmZmZjJAAAAAAAAAN0CZmZmZmZk7QA== + + 9.2000000e+00 1.3800000e+01 1.8400000e+01 1.3800000e+01 1.8400000e+01 2.3000000e+01 1.8400000e+01 2.3000000e+01 2.7600000e+01 - - SAAAAAAAAAAAAFdAAAAAAABAYUAAAAAAAABnQAAAAAAAQGFAAAAAAAAAZ0D//////79sQAAAAAAAAGdA//////+/bEAAAAAAAEBxQA== + + 9.2000000e+01 1.3800000e+02 1.8400000e+02 1.3800000e+02 1.8400000e+02 2.3000000e+02 1.8400000e+02 2.3000000e+02 2.7600000e+02 - - SAAAAGZmZmZmZhJAmZmZmZmZG0BmZmZmZmYiQJmZmZmZmRtAZmZmZmZmIkAAAAAAAAAnQGZmZmZmZiJAAAAAAAAAJ0CZmZmZmZkrQA== + + 4.6000000e+00 6.9000000e+00 9.2000000e+00 6.9000000e+00 9.2000000e+00 1.1500000e+01 9.2000000e+00 1.1500000e+01 1.3800000e+01 - - SAAAAAAAAAAAAEdAAAAAAABAUUAAAAAAAABXQAAAAAAAQFFAAAAAAAAAV0D//////79cQAAAAAAAAFdA//////+/XEAAAAAAAEBhQA== + + 4.6000000e+01 6.9000000e+01 9.2000000e+01 6.9000000e+01 9.2000000e+01 1.1500000e+02 9.2000000e+01 1.1500000e+02 1.3800000e+02 - - SAAAAGZmZmZmZiJAmZmZmZmZK0BmZmZmZmYyQJmZmZmZmStAZmZmZmZmMkAAAAAAAAA3QGZmZmZmZjJAAAAAAAAAN0CZmZmZmZk7QA== + + 9.2000000e+00 1.3800000e+01 1.8400000e+01 1.3800000e+01 1.8400000e+01 2.3000000e+01 1.8400000e+01 2.3000000e+01 2.7600000e+01 - - SAAAAAAAAAAAAFdAAAAAAABAYUAAAAAAAABnQAAAAAAAQGFAAAAAAAAAZ0D//////79sQAAAAAAAAGdA//////+/bEAAAAAAAEBxQA== + + 9.2000000e+01 1.3800000e+02 1.8400000e+02 1.3800000e+02 1.8400000e+02 2.3000000e+02 1.8400000e+02 2.3000000e+02 2.7600000e+02 - - SAAAAGZmZmZmZhJAmZmZmZmZG0BmZmZmZmYiQJmZmZmZmRtAZmZmZmZmIkAAAAAAAAAnQGZmZmZmZiJAAAAAAAAAJ0CZmZmZmZkrQA== + + 4.6000000e+00 6.9000000e+00 9.2000000e+00 6.9000000e+00 9.2000000e+00 1.1500000e+01 9.2000000e+00 1.1500000e+01 1.3800000e+01 - - SAAAAAAAAAAAAEdAAAAAAABAUUAAAAAAAABXQAAAAAAAQFFAAAAAAAAAV0D//////79cQAAAAAAAAFdA//////+/XEAAAAAAAEBhQA== + + 4.6000000e+01 6.9000000e+01 9.2000000e+01 6.9000000e+01 9.2000000e+01 1.1500000e+02 9.2000000e+01 1.1500000e+02 1.3800000e+02 - - SAAAAGZmZmZmZiJAmZmZmZmZK0BmZmZmZmYyQJmZmZmZmStAZmZmZmZmMkAAAAAAAAA3QGZmZmZmZjJAAAAAAAAAN0CZmZmZmZk7QA== + + 9.2000000e+00 1.3800000e+01 1.8400000e+01 1.3800000e+01 1.8400000e+01 2.3000000e+01 1.8400000e+01 2.3000000e+01 2.7600000e+01 - - SAAAAAAAAAAAAFdAAAAAAABAYUAAAAAAAABnQAAAAAAAQGFAAAAAAAAAZ0D//////79sQAAAAAAAAGdA//////+/bEAAAAAAAEBxQA== + + 9.2000000e+01 1.3800000e+02 1.8400000e+02 1.3800000e+02 1.8400000e+02 2.3000000e+02 1.8400000e+02 2.3000000e+02 2.7600000e+02 - - SAAAAGZmZmZmZhJAmZmZmZmZG0BmZmZmZmYiQJmZmZmZmRtAZmZmZmZmIkAAAAAAAAAnQGZmZmZmZiJAAAAAAAAAJ0CZmZmZmZkrQA== + + 4.6000000e+00 6.9000000e+00 9.2000000e+00 6.9000000e+00 9.2000000e+00 1.1500000e+01 9.2000000e+00 1.1500000e+01 1.3800000e+01 - - SAAAAAAAAAAAAEdAAAAAAABAUUAAAAAAAABXQAAAAAAAQFFAAAAAAAAAV0D//////79cQAAAAAAAAFdA//////+/XEAAAAAAAEBhQA== + + 4.6000000e+01 6.9000000e+01 9.2000000e+01 6.9000000e+01 9.2000000e+01 1.1500000e+02 9.2000000e+01 1.1500000e+02 1.3800000e+02 - - GAAAAAAAAAAAADdAmZmZmZmZO0CZmZmZmRlAQA== + + 2.3000000e+01 2.7600000e+01 3.2200000e+01 - - GAAAAP//////v2xAAAAAAABAcUAAAAAAACB0QA== + + 2.3000000e+02 2.7600000e+02 3.2200000e+02 - - GAAAAAAAAAAAACdAmZmZmZmZK0CZmZmZmRkwQA== + + 1.1500000e+01 1.3800000e+01 1.6100000e+01 - - GAAAAP//////v1xAAAAAAABAYUAAAAAAACBkQA== + + 1.1500000e+02 1.3800000e+02 1.6100000e+02 - - GAAAAAAAAAAAADdAmZmZmZmZO0CZmZmZmRlAQA== + + 2.3000000e+01 2.7600000e+01 3.2200000e+01 - - GAAAAP//////v2xAAAAAAABAcUAAAAAAACB0QA== + + 2.3000000e+02 2.7600000e+02 3.2200000e+02 - - GAAAAAAAAAAAACdAmZmZmZmZK0CZmZmZmRkwQA== + + 1.1500000e+01 1.3800000e+01 1.6100000e+01 - - GAAAAP//////v1xAAAAAAABAYUAAAAAAACBkQA== + + 1.1500000e+02 1.3800000e+02 1.6100000e+02 - - GAAAAAAAAAAAADdAmZmZmZmZO0CZmZmZmRlAQA== + + 2.3000000e+01 2.7600000e+01 3.2200000e+01 - - GAAAAP//////v2xAAAAAAABAcUAAAAAAACB0QA== + + 2.3000000e+02 2.7600000e+02 3.2200000e+02 - - GAAAAAAAAAAAACdAmZmZmZmZK0CZmZmZmRkwQA== + + 1.1500000e+01 1.3800000e+01 1.6100000e+01 - - GAAAAP//////v1xAAAAAAABAYUAAAAAAACBkQA== + + 1.1500000e+02 1.3800000e+02 1.6100000e+02 - - GAAAAAAAAAAAADdAmZmZmZmZO0CZmZmZmRlAQA== + + 2.3000000e+01 2.7600000e+01 3.2200000e+01 - - GAAAAP//////v2xAAAAAAABAcUAAAAAAACB0QA== + + 2.3000000e+02 2.7600000e+02 3.2200000e+02 - - GAAAAAAAAAAAACdAmZmZmZmZK0CZmZmZmRkwQA== + + 1.1500000e+01 1.3800000e+01 1.6100000e+01 - - GAAAAP//////v1xAAAAAAABAYUAAAAAAACBkQA== + + 1.1500000e+02 1.3800000e+02 1.6100000e+02 - - GAAAAAAAAAAAADdAmZmZmZmZO0CZmZmZmRlAQA== + + 2.3000000e+01 2.7600000e+01 3.2200000e+01 - - GAAAAP//////v2xAAAAAAABAcUAAAAAAACB0QA== + + 2.3000000e+02 2.7600000e+02 3.2200000e+02 - - GAAAAAAAAAAAACdAmZmZmZmZK0CZmZmZmRkwQA== + + 1.1500000e+01 1.3800000e+01 1.6100000e+01 - - GAAAAP//////v1xAAAAAAABAYUAAAAAAACBkQA== + + 1.1500000e+02 1.3800000e+02 1.6100000e+02 - - GAAAAAAAAAAAADdAmZmZmZmZO0CZmZmZmRlAQA== + + 2.3000000e+01 2.7600000e+01 3.2200000e+01 - - GAAAAP//////v2xAAAAAAABAcUAAAAAAACB0QA== + + 2.3000000e+02 2.7600000e+02 3.2200000e+02 - - GAAAAAAAAAAAACdAmZmZmZmZK0CZmZmZmRkwQA== + + 1.1500000e+01 1.3800000e+01 1.6100000e+01 - - GAAAAP//////v1xAAAAAAABAYUAAAAAAACBkQA== + + 1.1500000e+02 1.3800000e+02 1.6100000e+02 diff --git a/applications/OptimizationApplication/tests/process_tests/test_2_orig.vtu b/applications/OptimizationApplication/tests/process_tests/test_2_orig.vtu index 103d83859e37..46a8312f1df7 100644 --- a/applications/OptimizationApplication/tests/process_tests/test_2_orig.vtu +++ b/applications/OptimizationApplication/tests/process_tests/test_2_orig.vtu @@ -1,96 +1,97 @@ - + + - + - - YAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPA/AAAAAAAA8D8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA8D8AAAAAAAAAAA== + + 0.0000000e+00 0.0000000e+00 0.0000000e+00 1.0000000e+00 0.0000000e+00 0.0000000e+00 1.0000000e+00 1.0000000e+00 0.0000000e+00 0.0000000e+00 1.0000000e+00 0.0000000e+00 - - EAAAAAAAAAABAAAAAgAAAAMAAAA= + + 0 1 2 3 - - BAAAAAQAAAA= + + 4 - - AQAAAAk= + + 9 - - YAAAAGZmZmZmZiJAmZmZmZmZK0BmZmZmZmYyQJmZmZmZmStAZmZmZmZmMkAAAAAAAAA3QGZmZmZmZjJAAAAAAAAAN0CZmZmZmZk7QAAAAAAAADdAmZmZmZmZO0CZmZmZmRlAQA== + + 9.2000000e+00 1.3800000e+01 1.8400000e+01 1.3800000e+01 1.8400000e+01 2.3000000e+01 1.8400000e+01 2.3000000e+01 2.7600000e+01 2.3000000e+01 2.7600000e+01 3.2200000e+01 - - YAAAAAAAAAAAAFdAAAAAAABAYUAAAAAAAABnQAAAAAAAQGFAAAAAAAAAZ0D//////79sQAAAAAAAAGdA//////+/bEAAAAAAAEBxQP//////v2xAAAAAAABAcUAAAAAAACB0QA== + + 9.2000000e+01 1.3800000e+02 1.8400000e+02 1.3800000e+02 1.8400000e+02 2.3000000e+02 1.8400000e+02 2.3000000e+02 2.7600000e+02 2.3000000e+02 2.7600000e+02 3.2200000e+02 - - YAAAAGZmZmZmZhJAmZmZmZmZG0BmZmZmZmYiQJmZmZmZmRtAZmZmZmZmIkAAAAAAAAAnQGZmZmZmZiJAAAAAAAAAJ0CZmZmZmZkrQAAAAAAAACdAmZmZmZmZK0CZmZmZmRkwQA== + + 4.6000000e+00 6.9000000e+00 9.2000000e+00 6.9000000e+00 9.2000000e+00 1.1500000e+01 9.2000000e+00 1.1500000e+01 1.3800000e+01 1.1500000e+01 1.3800000e+01 1.6100000e+01 - - YAAAAAAAAAAAAEdAAAAAAABAUUAAAAAAAABXQAAAAAAAQFFAAAAAAAAAV0D//////79cQAAAAAAAAFdA//////+/XEAAAAAAAEBhQP//////v1xAAAAAAABAYUAAAAAAACBkQA== + + 4.6000000e+01 6.9000000e+01 9.2000000e+01 6.9000000e+01 9.2000000e+01 1.1500000e+02 9.2000000e+01 1.1500000e+02 1.3800000e+02 1.1500000e+02 1.3800000e+02 1.6100000e+02 - - YAAAAGZmZmZmZiJAmZmZmZmZK0BmZmZmZmYyQJmZmZmZmStAZmZmZmZmMkAAAAAAAAA3QGZmZmZmZjJAAAAAAAAAN0CZmZmZmZk7QAAAAAAAADdAmZmZmZmZO0CZmZmZmRlAQA== + + 9.2000000e+00 1.3800000e+01 1.8400000e+01 1.3800000e+01 1.8400000e+01 2.3000000e+01 1.8400000e+01 2.3000000e+01 2.7600000e+01 2.3000000e+01 2.7600000e+01 3.2200000e+01 - - YAAAAAAAAAAAAFdAAAAAAABAYUAAAAAAAABnQAAAAAAAQGFAAAAAAAAAZ0D//////79sQAAAAAAAAGdA//////+/bEAAAAAAAEBxQP//////v2xAAAAAAABAcUAAAAAAACB0QA== + + 9.2000000e+01 1.3800000e+02 1.8400000e+02 1.3800000e+02 1.8400000e+02 2.3000000e+02 1.8400000e+02 2.3000000e+02 2.7600000e+02 2.3000000e+02 2.7600000e+02 3.2200000e+02 - - YAAAAGZmZmZmZhJAmZmZmZmZG0BmZmZmZmYiQJmZmZmZmRtAZmZmZmZmIkAAAAAAAAAnQGZmZmZmZiJAAAAAAAAAJ0CZmZmZmZkrQAAAAAAAACdAmZmZmZmZK0CZmZmZmRkwQA== + + 4.6000000e+00 6.9000000e+00 9.2000000e+00 6.9000000e+00 9.2000000e+00 1.1500000e+01 9.2000000e+00 1.1500000e+01 1.3800000e+01 1.1500000e+01 1.3800000e+01 1.6100000e+01 - - YAAAAAAAAAAAAEdAAAAAAABAUUAAAAAAAABXQAAAAAAAQFFAAAAAAAAAV0D//////79cQAAAAAAAAFdA//////+/XEAAAAAAAEBhQP//////v1xAAAAAAABAYUAAAAAAACBkQA== + + 4.6000000e+01 6.9000000e+01 9.2000000e+01 6.9000000e+01 9.2000000e+01 1.1500000e+02 9.2000000e+01 1.1500000e+02 1.3800000e+02 1.1500000e+02 1.3800000e+02 1.6100000e+02 - - YAAAAGZmZmZmZiJAmZmZmZmZK0BmZmZmZmYyQJmZmZmZmStAZmZmZmZmMkAAAAAAAAA3QGZmZmZmZjJAAAAAAAAAN0CZmZmZmZk7QAAAAAAAADdAmZmZmZmZO0CZmZmZmRlAQA== + + 9.2000000e+00 1.3800000e+01 1.8400000e+01 1.3800000e+01 1.8400000e+01 2.3000000e+01 1.8400000e+01 2.3000000e+01 2.7600000e+01 2.3000000e+01 2.7600000e+01 3.2200000e+01 - - YAAAAAAAAAAAAFdAAAAAAABAYUAAAAAAAABnQAAAAAAAQGFAAAAAAAAAZ0D//////79sQAAAAAAAAGdA//////+/bEAAAAAAAEBxQP//////v2xAAAAAAABAcUAAAAAAACB0QA== + + 9.2000000e+01 1.3800000e+02 1.8400000e+02 1.3800000e+02 1.8400000e+02 2.3000000e+02 1.8400000e+02 2.3000000e+02 2.7600000e+02 2.3000000e+02 2.7600000e+02 3.2200000e+02 - - YAAAAGZmZmZmZhJAmZmZmZmZG0BmZmZmZmYiQJmZmZmZmRtAZmZmZmZmIkAAAAAAAAAnQGZmZmZmZiJAAAAAAAAAJ0CZmZmZmZkrQAAAAAAAACdAmZmZmZmZK0CZmZmZmRkwQA== + + 4.6000000e+00 6.9000000e+00 9.2000000e+00 6.9000000e+00 9.2000000e+00 1.1500000e+01 9.2000000e+00 1.1500000e+01 1.3800000e+01 1.1500000e+01 1.3800000e+01 1.6100000e+01 - - YAAAAAAAAAAAAEdAAAAAAABAUUAAAAAAAABXQAAAAAAAQFFAAAAAAAAAV0D//////79cQAAAAAAAAFdA//////+/XEAAAAAAAEBhQP//////v1xAAAAAAABAYUAAAAAAACBkQA== + + 4.6000000e+01 6.9000000e+01 9.2000000e+01 6.9000000e+01 9.2000000e+01 1.1500000e+02 9.2000000e+01 1.1500000e+02 1.3800000e+02 1.1500000e+02 1.3800000e+02 1.6100000e+02 - - GAAAAGZmZmZmZiJAmZmZmZmZK0BmZmZmZmYyQA== + + 9.2000000e+00 1.3800000e+01 1.8400000e+01 - - GAAAAAAAAAAAAFdAAAAAAABAYUAAAAAAAABnQA== + + 9.2000000e+01 1.3800000e+02 1.8400000e+02 - - GAAAAGZmZmZmZhJAmZmZmZmZG0BmZmZmZmYiQA== + + 4.6000000e+00 6.9000000e+00 9.2000000e+00 - - GAAAAAAAAAAAAEdAAAAAAABAUUAAAAAAAABXQA== + + 4.6000000e+01 6.9000000e+01 9.2000000e+01 - - GAAAAGZmZmZmZiJAmZmZmZmZK0BmZmZmZmYyQA== + + 9.2000000e+00 1.3800000e+01 1.8400000e+01 - - GAAAAAAAAAAAAFdAAAAAAABAYUAAAAAAAABnQA== + + 9.2000000e+01 1.3800000e+02 1.8400000e+02 - - GAAAAGZmZmZmZhJAmZmZmZmZG0BmZmZmZmYiQA== + + 4.6000000e+00 6.9000000e+00 9.2000000e+00 - - GAAAAAAAAAAAAEdAAAAAAABAUUAAAAAAAABXQA== + + 4.6000000e+01 6.9000000e+01 9.2000000e+01 - - GAAAAGZmZmZmZiJAmZmZmZmZK0BmZmZmZmYyQA== + + 9.2000000e+00 1.3800000e+01 1.8400000e+01 - - GAAAAAAAAAAAAFdAAAAAAABAYUAAAAAAAABnQA== + + 9.2000000e+01 1.3800000e+02 1.8400000e+02 - - GAAAAGZmZmZmZhJAmZmZmZmZG0BmZmZmZmYiQA== + + 4.6000000e+00 6.9000000e+00 9.2000000e+00 - - GAAAAAAAAAAAAEdAAAAAAABAUUAAAAAAAABXQA== + + 4.6000000e+01 6.9000000e+01 9.2000000e+01 diff --git a/applications/OptimizationApplication/tests/process_tests/test_optimization_problem_vtu_output_process.py b/applications/OptimizationApplication/tests/process_tests/test_optimization_problem_vtu_output_process.py index b961f5ce53fb..8446a7ac1fd1 100644 --- a/applications/OptimizationApplication/tests/process_tests/test_optimization_problem_vtu_output_process.py +++ b/applications/OptimizationApplication/tests/process_tests/test_optimization_problem_vtu_output_process.py @@ -3,7 +3,7 @@ # Import KratosUnittest import KratosMultiphysics as Kratos import KratosMultiphysics.KratosUnittest as kratos_unittest -import KratosMultiphysics.OptimizationApplication as KratosOA +import KratosMultiphysics.kratos_utilities as kratos_utilities from KratosMultiphysics.OptimizationApplication.responses.response_function import ResponseFunction from KratosMultiphysics.OptimizationApplication.controls.control import Control from KratosMultiphysics.OptimizationApplication.execution_policies.execution_policy import ExecutionPolicy @@ -11,7 +11,7 @@ from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView from KratosMultiphysics.OptimizationApplication.utilities.buffered_dict import BufferedDict from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem -from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import ContainerExpressionTypes, SupportedSensitivityFieldVariableTypes +from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes from KratosMultiphysics.compare_two_files_check_process import CompareTwoFilesCheckProcess class TestOptimizationProblemVtuOutputProcess(kratos_unittest.TestCase): @@ -21,7 +21,7 @@ def __init__(self, response_name: str, model_part: Kratos.ModelPart) -> None: self.model_part = model_part def CalculateValue(self) -> float: return 0.0 - def CalculateGradient(self, physical_variable_collective_expressions: 'dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]') -> None: + def CalculateGradient(self, physical_variable_combined_tensor_adaptors: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]') -> None: pass def Check(self) -> None: pass @@ -44,15 +44,15 @@ def Initialize(self) -> None: pass def Finalize(self) -> None: pass - def GetControlField(self) -> ContainerExpressionTypes: + def GetControlField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: return None - def GetEmptyField(self) -> ContainerExpressionTypes: + def GetEmptyField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: return None def GetPhysicalKratosVariables(self) -> 'list[SupportedSensitivityFieldVariableTypes]': return [] - def MapGradient(self, physical_gradient_variable_container_expression_map: 'dict[SupportedSensitivityFieldVariableTypes, ContainerExpressionTypes]') -> ContainerExpressionTypes: + def MapGradient(self, physical_gradient_variable_tensor_adaptor_map: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleTensorAdaptor]') -> Kratos.TensorAdaptors.DoubleTensorAdaptor: return None - def Update(self, control_field: ContainerExpressionTypes) -> bool: + def Update(self, control_field: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> bool: return True class DummyExecutionPolicy(ExecutionPolicy): @@ -119,25 +119,34 @@ def setUpClass(cls) -> None: def __AddData(self, buffered_dict: BufferedDict, is_buffered_data: bool, component): step_v = self.optimization_problem.GetStep() + 1 - - nodal_data = Kratos.Expression.NodalExpression(component.model_part) - Kratos.Expression.VariableExpressionIO.Read(nodal_data, Kratos.VELOCITY, False) - buffered_dict[f"{component.GetName()}_data_nodal_vel__{is_buffered_data}"] = nodal_data * step_v * 2.3 - - element_data = Kratos.Expression.ElementExpression(component.model_part) - Kratos.Expression.VariableExpressionIO.Read(element_data, Kratos.ACCELERATION) - buffered_dict[f"{component.GetName()}_data_element_acc_{is_buffered_data}"] = element_data * step_v * 2.3 - - collective_data = KratosOA.CollectiveExpression([nodal_data, element_data]) - collective_data *= 2.0 - buffered_dict[f"{component.GetName()}_collective_element_{is_buffered_data}"] = collective_data * step_v * 2.3 + # purposefully ignored to always overwrite to the same step = 0 file. + # self.model_part1.ProcessInfo[Kratos.STEP] = step_v + # self.model_part2.ProcessInfo[Kratos.STEP] = step_v + self.model_part1.ProcessInfo[Kratos.TIME] = step_v + self.model_part2.ProcessInfo[Kratos.TIME] = step_v + + nodal_data = Kratos.TensorAdaptors.VariableTensorAdaptor(component.model_part.Nodes, Kratos.VELOCITY) + nodal_data.CollectData() + nodal_data.data[:] *= step_v * 2.3 + buffered_dict[f"{component.GetName()}_data_nodal_vel__{is_buffered_data}"] = nodal_data + + element_data = Kratos.TensorAdaptors.VariableTensorAdaptor(component.model_part.Elements, Kratos.ACCELERATION) + element_data.CollectData() + element_data.data[:] *= step_v * 2.3 + buffered_dict[f"{component.GetName()}_data_element_acc_{is_buffered_data}"] = element_data + + combined_data = Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([nodal_data, element_data]) + combined_data.CollectData() + combined_data.data[:] *= 2.0 * step_v * 2.3 + Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(combined_data, perform_store_data_recursively=False, copy=False).StoreData() + buffered_dict[f"{component.GetName()}_combined_element_{is_buffered_data}"] = combined_data def test_OptimizationProblemVtuOutputProcess(self): parameters = Kratos.Parameters( """ { "file_name" : "", - "file_format" : "binary", + "file_format" : "ascii", "write_deformed_configuration": false, "list_of_output_components" : ["all"], "output_precision" : 7, @@ -147,7 +156,7 @@ def test_OptimizationProblemVtuOutputProcess(self): """ ) - process = OptimizationProblemVtuOutputProcess(parameters, self.optimization_problem) + process = OptimizationProblemVtuOutputProcess(self.model, parameters, self.optimization_problem) process.ExecuteInitialize() # initialize unbuffered data @@ -169,7 +178,7 @@ def test_OptimizationProblemVtuOutputProcess(self): CompareTwoFilesCheckProcess(Kratos.Parameters(""" { "reference_file_name" : "test_1_orig.vtu", - "output_file_name" : "Optimization_Results/test_1.vtu", + "output_file_name" : "Optimization_Results/test_1/test_1_elements_0.vtu", "remove_output_file" : true, "comparison_type" : "deterministic" }""")).Execute() @@ -177,10 +186,15 @@ def test_OptimizationProblemVtuOutputProcess(self): CompareTwoFilesCheckProcess(Kratos.Parameters(""" { "reference_file_name" : "test_2_orig.vtu", - "output_file_name" : "Optimization_Results/test_2.vtu", + "output_file_name" : "Optimization_Results/test_2/test_2_elements_0.vtu", "remove_output_file" : true, "comparison_type" : "deterministic" }""")).Execute() + @classmethod + def tearDownClass(cls): + with kratos_unittest.WorkFolderScope(".", __file__): + kratos_utilities.DeleteDirectoryIfExisting("Optimization_Results") + if __name__ == "__main__": kratos_unittest.main() From 7df313172c688532d7d0696712c651545ceb4d7f Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 13 Feb 2026 12:24:51 +0100 Subject: [PATCH 084/116] update scipy algorithms --- .../algorithms/SciPy_algorithms.py | 17 +++++------- .../standardized_SciPy_constraint.py | 27 +++++++++---------- .../standardized_SciPy_objective.py | 25 +++++++++-------- .../optimization_parameters.json | 10 +++---- .../slsqp_shell_thickness_opt/summary_ref.csv | 3 ++- .../test_sqp_optimizer.py | 3 --- 6 files changed, 38 insertions(+), 47 deletions(-) diff --git a/applications/OptimizationApplication/python_scripts/algorithms/SciPy_algorithms.py b/applications/OptimizationApplication/python_scripts/algorithms/SciPy_algorithms.py index 3460cae75543..e528dfd9a06a 100644 --- a/applications/OptimizationApplication/python_scripts/algorithms/SciPy_algorithms.py +++ b/applications/OptimizationApplication/python_scripts/algorithms/SciPy_algorithms.py @@ -1,5 +1,4 @@ import KratosMultiphysics as Kratos -import KratosMultiphysics.OptimizationApplication as KratosOA from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem from KratosMultiphysics.OptimizationApplication.algorithms.standardized_SciPy_objective import StandardizedSciPyObjective from KratosMultiphysics.OptimizationApplication.algorithms.standardized_SciPy_constraint import StandardizedSciPyConstraint @@ -70,7 +69,7 @@ def __init__(self, model:Kratos.Model, parameters: Kratos.Parameters, optimizati self.bounds = scipy.optimize.Bounds(lb=self.SciPy_settings["lower_bound"].GetDouble(), ub=self.SciPy_settings["upper_bound"].GetDouble()) self.__kratos_constraints = [] self.__scipy_constraints = [] - for constraint_settings in parameters["constraints"]: + for constraint_settings in parameters["constraints"].values(): constraint = StandardizedSciPyConstraint(constraint_settings, self.master_control, self._optimization_problem) self.__kratos_constraints.append(constraint) self._optimization_problem.AddComponent(constraint) @@ -79,10 +78,6 @@ def __init__(self, model:Kratos.Model, parameters: Kratos.Parameters, optimizati scipy_constraint = NonlinearConstraint(constraint.CalculateStandardizedValue, constraint.GetLowerBound(), constraint.GetUpperBound(), constraint.CalculateStandardizedGradient) self.__scipy_constraints.append(scipy_constraint) - - - - def GetMinimumBufferSize(self) -> int: return 2 @@ -101,7 +96,7 @@ def Initialize(self): self.algorithm_data.SetDataBuffer(self.GetMinimumBufferSize()) # create nlopt optimizer - self.x0 = self.__control_field.Evaluate().reshape(-1) + self.x0 = self.__control_field.data.reshape(-1) @time_decorator() def Finalize(self): @@ -121,14 +116,14 @@ def Solve(self): Kratos.Logger.PrintInfo(self.__class__.__name__, f"res::message: {res.message}") @time_decorator() - def Output(self, *args) -> KratosOA.CollectiveExpression: + def Output(self, *args) -> Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor: # SciPy calls it at the end of each optimization iterations. Sometime it doesn't call f(x) during iteration, hence to avoid lack of data in the buffer we have a flag "computed" here. if self.__objective.computed: Kratos.Logger.PrintInfo(self.__class__.__name__, f"Output iteration {self._optimization_problem.GetStep()}") - shape = [c.GetItemShape() for c in self.__control_field.GetContainerExpressions()] - KratosOA.CollectiveExpressionIO.Read(self.__control_field, args[0], shape) + self.__control_field.data[:] = args[0] + Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(self.__control_field, perform_store_data_recursively=False, copy=False).StoreData() self.algorithm_data.GetBufferedData().SetValue("control_field", self.__control_field.Clone(), overwrite=True) OutputGradientFields(self.__objective, self._optimization_problem, True) @@ -137,7 +132,7 @@ def Output(self, *args) -> KratosOA.CollectiveExpression: for process in self._optimization_problem.GetListOfProcesses("output_processes"): if process.IsOutputStep(): process.PrintOutput() - + # Advance in Optimization Iteration self._optimization_problem.AdvanceStep() self.__objective.computed = False diff --git a/applications/OptimizationApplication/python_scripts/algorithms/standardized_SciPy_constraint.py b/applications/OptimizationApplication/python_scripts/algorithms/standardized_SciPy_constraint.py index 3608d628c401..4f25351eceea 100644 --- a/applications/OptimizationApplication/python_scripts/algorithms/standardized_SciPy_constraint.py +++ b/applications/OptimizationApplication/python_scripts/algorithms/standardized_SciPy_constraint.py @@ -1,5 +1,4 @@ import KratosMultiphysics as Kratos -import KratosMultiphysics.OptimizationApplication as KratosOA from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem from KratosMultiphysics.OptimizationApplication.responses.response_routine import ResponseRoutine from KratosMultiphysics.OptimizationApplication.controls.master_control import MasterControl @@ -52,8 +51,8 @@ def __init__(self, parameters: Kratos.Parameters, master_control: MasterControl, def CalculateStandardizedValue(self, x:np.array, save_data: bool = True) -> float: control_field = self.GetMasterControl().GetEmptyField() - shape = [c.GetItemShape() for c in control_field.GetContainerExpressions()] - KratosOA.CollectiveExpressionIO.Read(control_field, x, shape) + control_field.data[:] = x + Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(control_field, perform_store_data_recursively=False, copy=False).StoreData() with TimeLogger(f"StandardizedObjective::Calculate {self.GetResponseName()} value", None, "Finished"): response_value = self.CalculateValue(control_field) @@ -81,36 +80,36 @@ def CalculateStandardizedGradient(self, x:np.array, save_field: bool = True) -> self.CalculateStandardizedValue(x, False) # Compute new primal if x has changed. Does nothing if x the same. with TimeLogger(f"StandardizedObjective::Calculate {self.GetResponseName()} gradients", None, "Finished"): - gradient_collective_expression = self.CalculateGradient() + gradient_combined_tensor_adaptor = self.CalculateGradient() if save_field: # save the physical gradients for post processing in unbuffered data container. for physical_var, physical_gradient in self.GetRequiredPhysicalGradients().items(): - for physical_gradient_expression in physical_gradient.GetContainerExpressions(): - variable_name = f"d{self.GetResponseName()}_d{physical_var.Name()}_{physical_gradient_expression.GetModelPart().Name}" + for physical_gradient_ta in physical_gradient.GetTensorAdaptors(): + variable_name = f"d{self.GetResponseName()}_d{physical_var.Name()}" if self.__unbuffered_data.HasValue(variable_name): del self.__unbuffered_data[variable_name] # cloning is a cheap operation, it only moves underlying pointers # does not create additional memory. - self.__unbuffered_data[variable_name] = physical_gradient_expression.Clone() + self.__unbuffered_data[variable_name] = physical_gradient_ta.Clone() # save the filtered gradients for post processing in unbuffered data container. - for gradient_container_expression, control in zip(gradient_collective_expression.GetContainerExpressions(), self.GetMasterControl().GetListOfControls()): - variable_name = f"d{self.GetResponseName()}_d{control.GetName()}_{physical_gradient_expression.GetModelPart().Name}" + for gradient_ta, control in zip(gradient_combined_tensor_adaptor.GetTensorAdaptors(), self.GetMasterControl().GetListOfControls()): + variable_name = f"d{self.GetResponseName()}_d{control.GetName()}" if self.__unbuffered_data.HasValue(variable_name): del self.__unbuffered_data[variable_name] # cloning is a cheap operation, it only moves underlying pointers # does not create additional memory. - self.__unbuffered_data[variable_name] = gradient_container_expression.Clone() - - return gradient_collective_expression.Evaluate().reshape(-1) + self.__unbuffered_data[variable_name] = gradient_ta.Clone() + + return gradient_combined_tensor_adaptor.data.reshape(-1) def GetValue(self, step_index: int = 0) -> float: return self.__buffered_data.GetValue("value", step_index) def GetStandardizedValue(self, step_index: int = 0) -> float: return self.GetValue(step_index) - self.GetStandardizedReferenceValue() - + def GetUpperBound(self): return self.upper_bound - + def GetLowerBound(self): return self.lower_bound diff --git a/applications/OptimizationApplication/python_scripts/algorithms/standardized_SciPy_objective.py b/applications/OptimizationApplication/python_scripts/algorithms/standardized_SciPy_objective.py index a956a7807740..eb10b97e34f0 100644 --- a/applications/OptimizationApplication/python_scripts/algorithms/standardized_SciPy_objective.py +++ b/applications/OptimizationApplication/python_scripts/algorithms/standardized_SciPy_objective.py @@ -1,5 +1,4 @@ import KratosMultiphysics as Kratos -import KratosMultiphysics.OptimizationApplication as KratosOA from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem from KratosMultiphysics.OptimizationApplication.controls.master_control import MasterControl from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView @@ -72,8 +71,8 @@ def GetInitialValue(self) -> float: def CalculateStandardizedValue(self, x:np.array, save_data: bool = True) -> float: control_field = self.GetMasterControl().GetEmptyField() - shape = [c.GetItemShape() for c in control_field.GetContainerExpressions()] - KratosOA.CollectiveExpressionIO.Read(control_field, x, shape) + control_field.data[:] = x + Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(control_field, perform_store_data_recursively=False, copy=False).StoreData() with TimeLogger(f"StandardizedObjective::Calculate {self.GetResponseName()} value", None, "Finished"): response_value = self.CalculateValue(control_field) @@ -81,7 +80,7 @@ def CalculateStandardizedValue(self, x:np.array, save_data: bool = True) -> floa if not self.__unbuffered_data.HasValue("initial_value"): self.__unbuffered_data["initial_value"] = response_value - + if save_data: if self.__buffered_data.HasValue("value"): del self.__buffered_data["value"] @@ -103,26 +102,26 @@ def CalculateStandardizedGradient(self, x:np.array, save_field: bool = True) -> self.CalculateStandardizedValue(x, False) # Compute new primal if x has changed. Does nothing if x the same with TimeLogger(f"StandardizedObjective::Calculate {self.GetResponseName()} gradients", None, "Finished"): - gradient_collective_expression = self.CalculateGradient() + gradient_combined_tensor_adaptor = self.CalculateGradient() if save_field: # save the physical gradients for post processing in unbuffered data container. for physical_var, physical_gradient in self.GetRequiredPhysicalGradients().items(): - for physical_gradient_expression in physical_gradient.GetContainerExpressions(): - variable_name = f"d{self.GetResponseName()}_d{physical_var.Name()}_{physical_gradient_expression.GetModelPart().Name}" + for physical_gradient_ta in physical_gradient.GetTensorAdaptors(): + variable_name = f"d{self.GetResponseName()}_d{physical_var.Name()}" if self.__unbuffered_data.HasValue(variable_name): del self.__unbuffered_data[variable_name] # cloning is a cheap operation, it only moves underlying pointers # does not create additional memory. - self.__unbuffered_data[variable_name] = physical_gradient_expression.Clone() + self.__unbuffered_data[variable_name] = physical_gradient_ta.Clone() # save the filtered gradients for post processing in unbuffered data container. - for gradient_container_expression, control in zip(gradient_collective_expression.GetContainerExpressions(), self.GetMasterControl().GetListOfControls()): - variable_name = f"d{self.GetResponseName()}_d{control.GetName()}_{physical_gradient_expression.GetModelPart().Name}" + for gradient_ta, control in zip(gradient_combined_tensor_adaptor.GetTensorAdaptors(), self.GetMasterControl().GetListOfControls()): + variable_name = f"d{self.GetResponseName()}_d{control.GetName()}" if self.__unbuffered_data.HasValue(variable_name): del self.__unbuffered_data[variable_name] # cloning is a cheap operation, it only moves underlying pointers # does not create additional memory. - self.__unbuffered_data[variable_name] = gradient_container_expression.Clone() - - return gradient_collective_expression.Evaluate().reshape(-1) * self.__scaling + self.__unbuffered_data[variable_name] = gradient_ta.Clone() + + return gradient_combined_tensor_adaptor.data.reshape(-1) * self.__scaling def GetRelativeChange(self) -> float: if self.__optimization_problem.GetStep() > 0: diff --git a/applications/OptimizationApplication/tests/algorithm_tests/scipy_tests/slsqp_shell_thickness_opt/optimization_parameters.json b/applications/OptimizationApplication/tests/algorithm_tests/scipy_tests/slsqp_shell_thickness_opt/optimization_parameters.json index 83e324abff6f..b7e371a801a2 100644 --- a/applications/OptimizationApplication/tests/algorithm_tests/scipy_tests/slsqp_shell_thickness_opt/optimization_parameters.json +++ b/applications/OptimizationApplication/tests/algorithm_tests/scipy_tests/slsqp_shell_thickness_opt/optimization_parameters.json @@ -71,18 +71,18 @@ "filter_radius": 0.2 } }, - "penalty_power": 1, "output_all_fields": false, "physical_thicknesses": [ 0.01, 0.1 ], - "beta_settings": { + "thickness_projection_settings": { + "type": "adaptive_sigmoidal_projection", "initial_value": 5, "max_value": 30, - "adaptive": true, "increase_fac": 1.05, - "update_period": 50 + "update_period": 50, + "penalty_factor": 1 } } } @@ -107,7 +107,7 @@ "constraints": [ { "response_expression": "strain_energy_shell", - "upper_boundary" : 0.002 + "upper_boundary": 0.002 } ] }, diff --git a/applications/OptimizationApplication/tests/algorithm_tests/scipy_tests/slsqp_shell_thickness_opt/summary_ref.csv b/applications/OptimizationApplication/tests/algorithm_tests/scipy_tests/slsqp_shell_thickness_opt/summary_ref.csv index 36c647a108eb..84e2e6f3cfd2 100644 --- a/applications/OptimizationApplication/tests/algorithm_tests/scipy_tests/slsqp_shell_thickness_opt/summary_ref.csv +++ b/applications/OptimizationApplication/tests/algorithm_tests/scipy_tests/slsqp_shell_thickness_opt/summary_ref.csv @@ -7,6 +7,7 @@ # initial_value: 3.8874e+03 # strain_energy_shell: # initial_value: 5.5273e-03 +# algorithm: # ------------ End of initial values ------------ # ----------------------------------------------- # ------------ Start of step values ------------- @@ -16,5 +17,5 @@ 1, 2.6746e+03, 1.5104e-03 2, 2.6811e+03, 1.5885e-03 3, 2.6677e+03, 1.5436e-03 - 4, 2.6191e+03, 1.5046e-03 + 4, 2.6841e+03, 1.5475e-03 # End of file \ No newline at end of file diff --git a/applications/OptimizationApplication/tests/algorithm_tests/scipy_tests/slsqp_shell_thickness_opt/test_sqp_optimizer.py b/applications/OptimizationApplication/tests/algorithm_tests/scipy_tests/slsqp_shell_thickness_opt/test_sqp_optimizer.py index 402946622a2c..c698ff2b3c5a 100644 --- a/applications/OptimizationApplication/tests/algorithm_tests/scipy_tests/slsqp_shell_thickness_opt/test_sqp_optimizer.py +++ b/applications/OptimizationApplication/tests/algorithm_tests/scipy_tests/slsqp_shell_thickness_opt/test_sqp_optimizer.py @@ -3,9 +3,6 @@ from KratosMultiphysics.OptimizationApplication.optimization_analysis import OptimizationAnalysis from KratosMultiphysics.compare_two_files_check_process import CompareTwoFilesCheckProcess - -import csv, os - try: import scipy except ImportError: From 0c660bd0c726407c74bd8aa8fc0fbb78ff145bd7 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 13 Feb 2026 12:34:49 +0100 Subject: [PATCH 085/116] update NLOpt contraint and obj --- .../standardized_NLOPT_constraint.py | 23 ++++++++++--------- .../standardized_NLOPT_objective.py | 22 ++++++++++-------- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/applications/OptimizationApplication/python_scripts/algorithms/standardized_NLOPT_constraint.py b/applications/OptimizationApplication/python_scripts/algorithms/standardized_NLOPT_constraint.py index 102adadd822a..d6782638a0af 100644 --- a/applications/OptimizationApplication/python_scripts/algorithms/standardized_NLOPT_constraint.py +++ b/applications/OptimizationApplication/python_scripts/algorithms/standardized_NLOPT_constraint.py @@ -114,11 +114,11 @@ def CalculateStandardizedValueAndGradients(self, control_field: numpy.ndarray, g DictLogger("Constraint info",self.GetInfo()) if gradient_field.size > 0: - gradient_collective_expression = self.CalculateGradient() - gradient_field[:] = gradient_collective_expression.Evaluate().reshape(-1) * self.GetStandardizationFactor() + gradient_combined_tensor_adaptor = self.CalculateGradient() + gradient_field[:] = gradient_combined_tensor_adaptor.data.reshape(-1) * self.GetStandardizationFactor() if save_value: - self.LogGradientFields(gradient_collective_expression) + self.LogGradientFields(gradient_combined_tensor_adaptor) return self.GetStandardizedValue() @@ -162,32 +162,33 @@ def LogValues(self) -> None: if self.__buffered_data.HasValue("violation [%]"): del self.__buffered_data["violation [%]"] self.__buffered_data["violation [%]"] = self.GetAbsoluteViolation() - def LogGradientFields(self,gradient_collective_expression) -> None: + def LogGradientFields(self, gradient_combined_tensor_adaptor: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor) -> None: # save the physical gradients for post processing in unbuffered data container. for physical_var, physical_gradient in self.GetRequiredPhysicalGradients().items(): variable_name = f"d{self.GetReponse().GetName()}_d{physical_var.Name()}" - for physical_gradient_expression in physical_gradient.GetContainerExpressions(): + for physical_gradient_ta in physical_gradient.GetTensorAdaptors(): if self.__unbuffered_data.HasValue(variable_name): del self.__unbuffered_data[variable_name] # cloning is a cheap operation, it only moves underlying pointers # does not create additional memory. - self.__unbuffered_data[variable_name] = physical_gradient_expression.Clone() + self.__unbuffered_data[variable_name] = physical_gradient_ta.Clone() # save the filtered gradients for post processing in unbuffered data container. - for gradient_container_expression, control in zip(gradient_collective_expression.GetContainerExpressions(), self.GetMasterControl().GetListOfControls()): + for gradient_ta, control in zip(gradient_combined_tensor_adaptor.GetTensorAdaptors(), self.GetMasterControl().GetListOfControls()): variable_name = f"d{self.GetReponse().GetName()}_d{control.GetName()}" if self.__unbuffered_data.HasValue(variable_name): del self.__unbuffered_data[variable_name] # cloning is a cheap operation, it only moves underlying pointers # does not create additional memory. - self.__unbuffered_data[variable_name] = gradient_container_expression.Clone() + self.__unbuffered_data[variable_name] = gradient_ta.Clone() def UpdateMasterControl(self, new_control_field: numpy.ndarray) -> None: master_control = self.GetMasterControl() - new_control_field_exp = master_control.GetEmptyField() + new_control_field_ta = master_control.GetEmptyField() number_of_entities = [] shapes = [] for control in master_control.GetListOfControls(): number_of_entities.append(len(control.GetControlField().GetContainer())) shapes.append(control.GetControlField().GetItemShape()) - KratosOA.CollectiveExpressionIO.Read(new_control_field_exp,new_control_field,shapes) + new_control_field_ta.data[:] = new_control_field + Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(new_control_field_ta, perform_store_data_recursively=False, copy=False).StoreData() # now update the master control - master_control.Update(new_control_field_exp) \ No newline at end of file + master_control.Update(new_control_field_ta) \ No newline at end of file diff --git a/applications/OptimizationApplication/python_scripts/algorithms/standardized_NLOPT_objective.py b/applications/OptimizationApplication/python_scripts/algorithms/standardized_NLOPT_objective.py index 1b486f9f582e..b261bb176e15 100644 --- a/applications/OptimizationApplication/python_scripts/algorithms/standardized_NLOPT_objective.py +++ b/applications/OptimizationApplication/python_scripts/algorithms/standardized_NLOPT_objective.py @@ -94,13 +94,13 @@ def CalculateStandardizedValueAndGradients(self, control_field: numpy.ndarray, g # compute gradients if gradient_field.size > 0: - self.gradient_collective_expression = self.CalculateGradient() + self.gradient_combined_tensor_adaptor = self.CalculateGradient() # save gradients if save_value: self.LogGradientFields() if gradient_field.size > 0: - gradient_field[:] = self.standardization_factor * self.gradient_collective_expression.Evaluate().reshape(-1) + gradient_field[:] = self.standardization_factor * self.gradient_combined_tensor_adaptor.data.reshape(-1) return self.standardized_response_value @@ -143,19 +143,19 @@ def LogGradientFields(self) -> None: # save the physical gradients for post processing in unbuffered data container. for physical_var, physical_gradient in self.GetRequiredPhysicalGradients().items(): variable_name = f"d{self.GetReponse().GetName()}_d{physical_var.Name()}" - for physical_gradient_expression in physical_gradient.GetContainerExpressions(): + for physical_gradient_ta in physical_gradient.GetTensorAdaptors(): if self.__unbuffered_data.HasValue(variable_name): del self.__unbuffered_data[variable_name] # cloning is a cheap operation, it only moves underlying pointers # does not create additional memory. - self.__unbuffered_data[variable_name] = physical_gradient_expression.Clone() + self.__unbuffered_data[variable_name] = physical_gradient_ta.Clone() # save the filtered gradients for post processing in unbuffered data container. - for gradient_container_expression, control in zip(self.gradient_collective_expression.GetContainerExpressions(), self.GetMasterControl().GetListOfControls()): + for gradient_ta, control in zip(self.gradient_combined_tensor_adaptor.GetTensorAdaptors(), self.GetMasterControl().GetListOfControls()): variable_name = f"d{self.GetReponse().GetName()}_d{control.GetName()}" if self.__unbuffered_data.HasValue(variable_name): del self.__unbuffered_data[variable_name] # cloning is a cheap operation, it only moves underlying pointers # does not create additional memory. - self.__unbuffered_data[variable_name] = gradient_container_expression.Clone() + self.__unbuffered_data[variable_name] = gradient_ta.Clone() def LogOptimizationStep(self) -> None: now = datetime.datetime.now() @@ -175,15 +175,17 @@ def UpdateMasterControlAndLogFields(self, new_control_field: numpy.ndarray) -> b CallOnAll(self.__optimization_problem.GetListOfProcesses("output_processes"), Kratos.OutputProcess.PrintOutput) self.LogOptimizationStep() self.__optimization_problem.AdvanceStep() - # convert numpy array to expression - new_control_field_exp = master_control.GetEmptyField() + # convert numpy array to tensor adaptor + new_control_field_cta = master_control.GetEmptyField() number_of_entities = [] shapes = [] for control in master_control.GetListOfControls(): number_of_entities.append(len(control.GetControlField().GetContainer())) shapes.append(control.GetControlField().GetItemShape()) - KratosOA.CollectiveExpressionIO.Read(new_control_field_exp,new_control_field,shapes) + + new_control_field_cta.data[:] = new_control_field + Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(new_control_field_cta, perform_store_data_recursively=False, copy=False).StoreData() # now update the master control - master_control.Update(new_control_field_exp) + master_control.Update(new_control_field_cta) master_control_updated = True return master_control_updated \ No newline at end of file From 339b915a9b46e30fd0cefef79ee42f0003a8bc46 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 13 Feb 2026 13:21:24 +0100 Subject: [PATCH 086/116] minor opt app fixes --- .../tests/algorithm_tests/test_algorithm_steepest_descent.py | 2 +- .../test_discrete_value_residual_response_function.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/applications/OptimizationApplication/tests/algorithm_tests/test_algorithm_steepest_descent.py b/applications/OptimizationApplication/tests/algorithm_tests/test_algorithm_steepest_descent.py index 0bc2e90762a7..4d91b5c8a35b 100644 --- a/applications/OptimizationApplication/tests/algorithm_tests/test_algorithm_steepest_descent.py +++ b/applications/OptimizationApplication/tests/algorithm_tests/test_algorithm_steepest_descent.py @@ -90,7 +90,7 @@ def test_Optimize(self): self.algorithm.Finalize() self.assertTrue(conv) self.assertEqual(self.algorithm.GetOptimizedObjectiveValue(), 14.249999999999998) - self.assertVectorAlmostEqual(self.algorithm.GetCurrentControlField().Evaluate(), [1.85, 3.7]) + self.assertVectorAlmostEqual(self.algorithm.GetCurrentControlField().data, [1.85, 3.7]) if __name__ == "__main__": kratos_unittest.main() \ No newline at end of file diff --git a/applications/OptimizationApplication/tests/responses_tests/test_discrete_value_residual_response_function.py b/applications/OptimizationApplication/tests/responses_tests/test_discrete_value_residual_response_function.py index 651f4ebf0be1..39cc8d092754 100644 --- a/applications/OptimizationApplication/tests/responses_tests/test_discrete_value_residual_response_function.py +++ b/applications/OptimizationApplication/tests/responses_tests/test_discrete_value_residual_response_function.py @@ -42,7 +42,7 @@ def test_CalculateValue(self): def test_CalculateGradient(self): ref_value = self.response_function.CalculateValue() analytical_gradient = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, Kratos.PRESSURE) - self.response_function.CalculateGradient({Kratos.PRESSURE: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([analytical_gradient])}) + self.response_function.CalculateGradient({Kratos.PRESSURE: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([analytical_gradient], copy=False)}) delta = 1e-9 for i, node in enumerate(self.model_part.Nodes): @@ -87,7 +87,7 @@ def test_CalculateValue(self): def test_CalculateGradient(self): ref_value = self.response_function.CalculateValue() analytical_gradient = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, Kratos.PRESSURE) - self.response_function.CalculateGradient({Kratos.PRESSURE: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([analytical_gradient])}) + self.response_function.CalculateGradient({Kratos.PRESSURE: Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor([analytical_gradient], copy=False)}) delta = 1e-8 for i, node in enumerate(self.model_part.Nodes): From 1936803e121e9d52e3e951bbd78b16697a8cee86 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 13 Feb 2026 13:44:53 +0100 Subject: [PATCH 087/116] update NLOPT algo --- .../python_scripts/algorithms/NLOPT_algorithms.py | 5 ++--- .../mma_shell_thickness_opt/test_mma_optimizer.py | 3 --- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/applications/OptimizationApplication/python_scripts/algorithms/NLOPT_algorithms.py b/applications/OptimizationApplication/python_scripts/algorithms/NLOPT_algorithms.py index 8f77b9a5ebf0..84631e5cffae 100644 --- a/applications/OptimizationApplication/python_scripts/algorithms/NLOPT_algorithms.py +++ b/applications/OptimizationApplication/python_scripts/algorithms/NLOPT_algorithms.py @@ -69,7 +69,7 @@ def __init__(self, model:Kratos.Model, parameters: Kratos.Parameters, optimizati self.__objective = StandardizedNLOPTObjective(parameters["objective"], self.master_control, self._optimization_problem) self._optimization_problem.AddComponent(self.__objective) self.__constraints = [] - for constraint_settings in parameters["constraints"]: + for constraint_settings in parameters["constraints"].values(): constraint = StandardizedNLOPTConstraint(constraint_settings, self.master_control, self._optimization_problem) self._optimization_problem.AddComponent(constraint) self.__constraints.append(constraint) @@ -128,8 +128,7 @@ def Initialize(self): self.algorithm_data = ComponentDataView("algorithm", self._optimization_problem) # create nlopt optimizer - self.x0 = self.__control_field.Evaluate() - self.x0 = self.x0.reshape(-1) + self.x0 = self.__control_field.data.reshape(-1) self.nlopt_optimizer = nlopt.opt(self.GetOptimizer(self.algorithm_name), self.x0.size) # add subsidiary optimization algorithm diff --git a/applications/OptimizationApplication/tests/algorithm_tests/nlopt_tests/mma_shell_thickness_opt/test_mma_optimizer.py b/applications/OptimizationApplication/tests/algorithm_tests/nlopt_tests/mma_shell_thickness_opt/test_mma_optimizer.py index addf77e110d9..81fd34cd6bb3 100644 --- a/applications/OptimizationApplication/tests/algorithm_tests/nlopt_tests/mma_shell_thickness_opt/test_mma_optimizer.py +++ b/applications/OptimizationApplication/tests/algorithm_tests/nlopt_tests/mma_shell_thickness_opt/test_mma_optimizer.py @@ -5,9 +5,6 @@ from KratosMultiphysics.compare_two_files_check_process import CompareTwoFilesCheckProcess from KratosMultiphysics.kratos_utilities import DeleteFileIfExisting - -import csv, os - try: import nlopt except ImportError: From 84b8c3bfd10459c33d654d8982a000b12175af5b Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 13 Feb 2026 15:55:24 +0100 Subject: [PATCH 088/116] remove ClipContainerExpression --- .../add_custom_utilities_to_python.cpp | 3 -- .../custom_utilities/control_utils.cpp | 29 ------------------- .../custom_utilities/control_utils.h | 7 ----- 3 files changed, 39 deletions(-) diff --git a/applications/SystemIdentificationApplication/custom_python/add_custom_utilities_to_python.cpp b/applications/SystemIdentificationApplication/custom_python/add_custom_utilities_to_python.cpp index 72761dc324a0..02fc52153e26 100644 --- a/applications/SystemIdentificationApplication/custom_python/add_custom_utilities_to_python.cpp +++ b/applications/SystemIdentificationApplication/custom_python/add_custom_utilities_to_python.cpp @@ -83,9 +83,6 @@ void AddCustomUtilitiesToPython(pybind11::module& m) auto control_utils = m.def_submodule("ControlUtils"); control_utils.def("AssignEquivalentProperties", &ControlUtils::AssignEquivalentProperties, py::arg("source_conditions"), py::arg("destination_conditions")); control_utils.def("AssignEquivalentProperties", &ControlUtils::AssignEquivalentProperties, py::arg("source_elements"), py::arg("destination_elements")); - control_utils.def("ClipContainerExpression", &ControlUtils::ClipContainerExpression, py::arg("nodal_expression"), py::arg("min"), py::arg("max")); - control_utils.def("ClipContainerExpression", &ControlUtils::ClipContainerExpression, py::arg("condition_expression"), py::arg("min"), py::arg("max")); - control_utils.def("ClipContainerExpression", &ControlUtils::ClipContainerExpression, py::arg("element_expression"), py::arg("min"), py::arg("max")); AddSmoothClamper(m, "Node"); AddSmoothClamper(m, "Condition"); diff --git a/applications/SystemIdentificationApplication/custom_utilities/control_utils.cpp b/applications/SystemIdentificationApplication/custom_utilities/control_utils.cpp index fb9402810230..6dc1d919786e 100644 --- a/applications/SystemIdentificationApplication/custom_utilities/control_utils.cpp +++ b/applications/SystemIdentificationApplication/custom_utilities/control_utils.cpp @@ -55,37 +55,8 @@ void ControlUtils::AssignEquivalentProperties( KRATOS_CATCH(""); } -template -void ControlUtils::ClipContainerExpression( - ContainerExpression& rContainerExpression, - const double Min, - const double Max) -{ - KRATOS_TRY - - const auto& r_expression = rContainerExpression.GetExpression(); - const auto number_of_entities = r_expression.NumberOfEntities(); - const auto number_of_components = r_expression.GetItemComponentCount(); - auto p_output_expression = LiteralFlatExpression::Create(number_of_entities, r_expression.GetItemShape()); - - IndexPartition(number_of_entities).for_each([&p_output_expression, &r_expression, number_of_components, Min, Max](const auto Index) { - const auto data_begin_index = Index * number_of_components; - for (IndexType i = 0; i < number_of_components; ++i) { - p_output_expression->SetData(data_begin_index, i, std::clamp(r_expression.Evaluate(Index, data_begin_index, i), Min, Max)); - } - }); - - rContainerExpression.SetExpression(p_output_expression); - - KRATOS_CATCH(""); -} - // template instantiations template KRATOS_API(SYSTEM_IDENTIFICATION_APPLICATION) void ControlUtils::AssignEquivalentProperties(ModelPart::ConditionsContainerType&, ModelPart::ConditionsContainerType&); template KRATOS_API(SYSTEM_IDENTIFICATION_APPLICATION) void ControlUtils::AssignEquivalentProperties(ModelPart::ElementsContainerType&, ModelPart::ElementsContainerType&); -template KRATOS_API(SYSTEM_IDENTIFICATION_APPLICATION) void ControlUtils::ClipContainerExpression(ContainerExpression&, const double, const double); -template KRATOS_API(SYSTEM_IDENTIFICATION_APPLICATION) void ControlUtils::ClipContainerExpression(ContainerExpression&, const double, const double); -template KRATOS_API(SYSTEM_IDENTIFICATION_APPLICATION) void ControlUtils::ClipContainerExpression(ContainerExpression&, const double, const double); - } /* namespace Kratos.*/ \ No newline at end of file diff --git a/applications/SystemIdentificationApplication/custom_utilities/control_utils.h b/applications/SystemIdentificationApplication/custom_utilities/control_utils.h index f3ac7d131b47..fae6c2734ff5 100644 --- a/applications/SystemIdentificationApplication/custom_utilities/control_utils.h +++ b/applications/SystemIdentificationApplication/custom_utilities/control_utils.h @@ -17,7 +17,6 @@ // Project includes #include "includes/model_part.h" -#include "expression/container_expression.h" // Application includes @@ -36,12 +35,6 @@ class KRATOS_API(SYSTEM_IDENTIFICATION_APPLICATION) ControlUtils TContainerType& rSourceContainer, TContainerType& rDestinationContainer); - template - static void ClipContainerExpression( - ContainerExpression& rContainerExpression, - const double Min, - const double Max); - ///@} }; From dc729357b6b7dc8ba050ffa1c4e67e442f2c7a62 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Sat, 14 Feb 2026 13:58:35 +0100 Subject: [PATCH 089/116] remove unused expression h --- .../custom_utilities/control_utils.cpp | 1 - .../system_identification_application_variables.h | 1 - 2 files changed, 2 deletions(-) diff --git a/applications/SystemIdentificationApplication/custom_utilities/control_utils.cpp b/applications/SystemIdentificationApplication/custom_utilities/control_utils.cpp index 6dc1d919786e..294e093f04ea 100644 --- a/applications/SystemIdentificationApplication/custom_utilities/control_utils.cpp +++ b/applications/SystemIdentificationApplication/custom_utilities/control_utils.cpp @@ -16,7 +16,6 @@ // Project includes #include "utilities/parallel_utilities.h" -#include "expression/literal_flat_expression.h" // Application includes diff --git a/applications/SystemIdentificationApplication/system_identification_application_variables.h b/applications/SystemIdentificationApplication/system_identification_application_variables.h index 067437adba67..d7d0eac01edb 100644 --- a/applications/SystemIdentificationApplication/system_identification_application_variables.h +++ b/applications/SystemIdentificationApplication/system_identification_application_variables.h @@ -21,7 +21,6 @@ // Project includes #include "containers/variable.h" #include "includes/define.h" -#include "expression/container_expression.h" namespace Kratos { From cc6ee55a92d6ff0a266975c794a34b0a8d6a48ac Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Tue, 17 Feb 2026 09:52:50 +0100 Subject: [PATCH 090/116] update smooth clamper to TA --- .../add_custom_utilities_to_python.cpp | 25 ++---- .../custom_utilities/smooth_clamper.cpp | 89 ++++++------------- .../custom_utilities/smooth_clamper.h | 23 +++-- .../tests/test_smooth_clamper.py | 41 +++++---- 4 files changed, 65 insertions(+), 113 deletions(-) diff --git a/applications/SystemIdentificationApplication/custom_python/add_custom_utilities_to_python.cpp b/applications/SystemIdentificationApplication/custom_python/add_custom_utilities_to_python.cpp index 02fc52153e26..3ee4f8c44d28 100644 --- a/applications/SystemIdentificationApplication/custom_python/add_custom_utilities_to_python.cpp +++ b/applications/SystemIdentificationApplication/custom_python/add_custom_utilities_to_python.cpp @@ -31,22 +31,6 @@ namespace Kratos::Python { -template -void AddSmoothClamper( - pybind11::module& m, - const std::string& rName) -{ - namespace py = pybind11; - - using smooth_clamper_type = SmoothClamper; - py::class_(m, (rName + "SmoothClamper").c_str()) - .def(py::init(), py::arg("min"), py::arg("max")) - .def("ProjectForward", py::overload_cast&>(&smooth_clamper_type::ProjectForward, py::const_), py::arg("x_expression")) - .def("CalculateForwardProjectionGradient", py::overload_cast&>(&smooth_clamper_type::CalculateForwardProjectionGradient, py::const_), py::arg("x_expression")) - .def("ProjectBackward", py::overload_cast&>(&smooth_clamper_type::ProjectBackward, py::const_), py::arg("y_expression")) - ; -} - template void AddMaskUtilsToPython(pybind11::module& m) { @@ -84,9 +68,12 @@ void AddCustomUtilitiesToPython(pybind11::module& m) control_utils.def("AssignEquivalentProperties", &ControlUtils::AssignEquivalentProperties, py::arg("source_conditions"), py::arg("destination_conditions")); control_utils.def("AssignEquivalentProperties", &ControlUtils::AssignEquivalentProperties, py::arg("source_elements"), py::arg("destination_elements")); - AddSmoothClamper(m, "Node"); - AddSmoothClamper(m, "Condition"); - AddSmoothClamper(m, "Element"); + py::class_(m, "SmoothClamper") + .def(py::init(), py::arg("min"), py::arg("max")) + .def("ProjectForward", py::overload_cast&>(&SmoothClamper::ProjectForward, py::const_), py::arg("x_tensor_adaptor")) + .def("CalculateForwardProjectionGradient", py::overload_cast&>(&SmoothClamper::CalculateForwardProjectionGradient, py::const_), py::arg("x_tensor_adaptor")) + .def("ProjectBackward", py::overload_cast&>(&SmoothClamper::ProjectBackward, py::const_), py::arg("y_tensor_adaptor")) + ; auto mask_utils = m.def_submodule("MaskUtils"); AddMaskUtilsToPython(mask_utils); diff --git a/applications/SystemIdentificationApplication/custom_utilities/smooth_clamper.cpp b/applications/SystemIdentificationApplication/custom_utilities/smooth_clamper.cpp index 4d2cda386cc4..e0046ec51160 100644 --- a/applications/SystemIdentificationApplication/custom_utilities/smooth_clamper.cpp +++ b/applications/SystemIdentificationApplication/custom_utilities/smooth_clamper.cpp @@ -15,7 +15,6 @@ // External includes // Project includes -#include "expression/literal_flat_expression.h" #include "utilities/parallel_utilities.h" // Application includes @@ -25,8 +24,7 @@ namespace Kratos { -template -SmoothClamper::SmoothClamper( +SmoothClamper::SmoothClamper( const double Min, const double Max) : mMin(Min), @@ -40,22 +38,19 @@ SmoothClamper::SmoothClamper( KRATOS_CATCH(""); } -template -double SmoothClamper::ProjectForward(const double X) const +double SmoothClamper::ProjectForward(const double X) const { const double x_tilde = std::clamp((X - mMin) / mDelta, 0.0, 1.0); return mMin + x_tilde * x_tilde * (3.0 - 2.0 * x_tilde) * mDelta; } -template -double SmoothClamper::CalculateForwardProjectionGradient(const double X) const +double SmoothClamper::CalculateForwardProjectionGradient(const double X) const { const double x_tilde = std::clamp((X - mMin) / mDelta, 0.0, 1.0); return 6 * x_tilde - 6 * x_tilde * x_tilde; } -template -double SmoothClamper::ProjectBackward(const double Y) const +double SmoothClamper::ProjectBackward(const double Y) const { double x_tilde; if (Y < mMin) { @@ -69,36 +64,26 @@ double SmoothClamper::ProjectBackward(const double Y) const return mMin + x_tilde * mDelta; } -template -ContainerExpression SmoothClamper::ProjectForward(const ContainerExpression& rInput) const +TensorAdaptor::Pointer SmoothClamper::ProjectForward(const TensorAdaptor& rInput) const { KRATOS_TRY // x*x*(3.0-2.0*x); - const auto& r_input_exp = rInput.GetExpression(); - const auto number_of_entities = r_input_exp.NumberOfEntities(); - const auto stride = r_input_exp.GetItemComponentCount(); + auto p_output = rInput.Clone(); + auto input_data_view = rInput.ViewData(); + auto output_data_view = p_output->ViewData(); - KRATOS_ERROR_IF_NOT(stride == 1) - << "SmoothClamper only supports scalar expressions. [ Expression stride = " << stride << " ].\n"; - - auto p_result_exp = LiteralFlatExpression::Create(number_of_entities, {}); - - IndexPartition(number_of_entities).for_each([&](const auto Index) { - const double x = r_input_exp.Evaluate(Index, Index, 0); - *(p_result_exp->begin() + Index) = this->ProjectForward(x); + IndexPartition(rInput.Size()).for_each([this, &output_data_view, &input_data_view](const auto Index) { + output_data_view[Index]= this->ProjectForward(input_data_view[Index]); }); - auto result = rInput; - result.SetExpression(p_result_exp); - return result; + return p_output; KRATOS_CATCH(""); } -template -ContainerExpression SmoothClamper::CalculateForwardProjectionGradient(const ContainerExpression& rInput) const +TensorAdaptor::Pointer SmoothClamper::CalculateForwardProjectionGradient(const TensorAdaptor& rInput) const { KRATOS_TRY @@ -106,57 +91,35 @@ ContainerExpression SmoothClamper::CalculateForw // y = 3x^2 - 2x^3 // dy/dx = 3.2.x - 2.3.x^2 - const auto& r_input_exp = rInput.GetExpression(); - const auto number_of_entities = r_input_exp.NumberOfEntities(); - const auto stride = r_input_exp.GetItemComponentCount(); - - KRATOS_ERROR_IF_NOT(stride == 1) - << "SmoothClamper only supports scalar expressions. [ Expression stride = " << stride << " ].\n"; + auto p_output = rInput.Clone(); + auto input_data_view = rInput.ViewData(); + auto output_data_view = p_output->ViewData(); - auto p_result_exp = LiteralFlatExpression::Create(number_of_entities, {}); - - IndexPartition(number_of_entities).for_each([&](const auto Index) { - const double x = r_input_exp.Evaluate(Index, Index, 0); - *(p_result_exp->begin() + Index) = this->CalculateForwardProjectionGradient(x); + IndexPartition(rInput.Size()).for_each([this, &output_data_view, &input_data_view](const auto Index) { + output_data_view[Index]= this->CalculateForwardProjectionGradient(input_data_view[Index]); }); - auto result = rInput; - result.SetExpression(p_result_exp); - return result; + return p_output; KRATOS_CATCH(""); } -template -ContainerExpression SmoothClamper::ProjectBackward(const ContainerExpression& rInput) const +TensorAdaptor::Pointer SmoothClamper::ProjectBackward(const TensorAdaptor& rInput) const { KRATOS_TRY - const auto& r_input_exp = rInput.GetExpression(); - const auto number_of_entities = r_input_exp.NumberOfEntities(); - const auto stride = r_input_exp.GetItemComponentCount(); - - KRATOS_ERROR_IF_NOT(stride == 1) - << "SmoothClamper only supports scalar expressions. [ Expression stride = " << stride << " ].\n"; + auto p_output = rInput.Clone(); + auto input_data_view = rInput.ViewData(); + auto output_data_view = p_output->ViewData(); - auto p_result_exp = LiteralFlatExpression::Create(number_of_entities, {}); - - IndexPartition(number_of_entities).for_each([&](const auto Index) { - const double x = r_input_exp.Evaluate(Index, Index, 0); - *(p_result_exp->begin() + Index) = this->ProjectBackward(x); + IndexPartition(rInput.Size()).for_each([this, &output_data_view, &input_data_view](const auto Index) { + output_data_view[Index]= this->ProjectBackward(input_data_view[Index]); }); - auto result = rInput; - result.SetExpression(p_result_exp); - return result; + + return p_output; KRATOS_CATCH(""); } - -// template instantiations -template class SmoothClamper; -template class SmoothClamper; -template class SmoothClamper; - } /* namespace Kratos.*/ \ No newline at end of file diff --git a/applications/SystemIdentificationApplication/custom_utilities/smooth_clamper.h b/applications/SystemIdentificationApplication/custom_utilities/smooth_clamper.h index 9548397e305b..6fb4a6fd334f 100644 --- a/applications/SystemIdentificationApplication/custom_utilities/smooth_clamper.h +++ b/applications/SystemIdentificationApplication/custom_utilities/smooth_clamper.h @@ -17,7 +17,7 @@ // Project includes #include "includes/define.h" -#include "expression/container_expression.h" +#include "tensor_adaptors/tensor_adaptor.h" // Application includes @@ -25,7 +25,6 @@ namespace Kratos { ///@name Kratos Classes ///@{ -template class KRATOS_API(SYSTEM_IDENTIFICATION_APPLICATION) SmoothClamper { public: @@ -74,29 +73,29 @@ class KRATOS_API(SYSTEM_IDENTIFICATION_APPLICATION) SmoothClamper double ProjectBackward(const double Y) const; /** - * @brief Clamps the given input expression smoothly. + * @brief Clamps the given input tensor adaptor smoothly. * @details The input value (x) can be in [-infty, +infty] range. But the output (y) will be in * [Min, Max] range. - * @param rX Input expression in input space. - * @return ContainerExpression Clamped output expression in clamped space. + * @param rX Input tensor adaptor in input space. + * @return TensorAdaptor::Pointer Clamped output tensor adaptor in clamped space. */ - ContainerExpression ProjectForward(const ContainerExpression& rX) const; + TensorAdaptor::Pointer ProjectForward(const TensorAdaptor& rX) const; /** * @brief Compute the derivative dy/dx at given X for clamping. * @details Computes the clamped derivative where clamped value is Y and input is X, and the * derivative is dY/dX - * @param rX Input expression in input space. - * @return ContainerExpression Output expression with dY/dX. + * @param rX Input tensor adaptor in input space. + * @return TensorAdaptor::Pointer Output tensor adaptor with dY/dX. */ - ContainerExpression CalculateForwardProjectionGradient(const ContainerExpression& rX) const; + TensorAdaptor::Pointer CalculateForwardProjectionGradient(const TensorAdaptor& rX) const; /** * @brief Computes the X given Y. - * @param rY Input expression in clamped space. - * @return ContainerExpression Output expression in input space. + * @param rY Input tensor adaptor in clamped space. + * @return TensorAdaptor::Pointer Output tensor adaptor in input space. */ - ContainerExpression ProjectBackward(const ContainerExpression& rY) const; + TensorAdaptor::Pointer ProjectBackward(const TensorAdaptor& rY) const; ///@} diff --git a/applications/SystemIdentificationApplication/tests/test_smooth_clamper.py b/applications/SystemIdentificationApplication/tests/test_smooth_clamper.py index 9120789f4d75..b4ccdb688cbd 100644 --- a/applications/SystemIdentificationApplication/tests/test_smooth_clamper.py +++ b/applications/SystemIdentificationApplication/tests/test_smooth_clamper.py @@ -13,39 +13,42 @@ def setUpClass(cls) -> None: cls.max = 150 for i in range(101): - node = cls.model_part.CreateNewNode(i + 1, i + 1, i + 2, i + 3) + node: Kratos.Node = cls.model_part.CreateNewNode(i + 1, i + 1, i + 2, i + 3) v = cls.min + float(i) * (cls.max - cls.min) / 100.0 node.SetValue(Kratos.PRESSURE, v) - cls.x_exp = Kratos.Expression.NodalExpression(cls.model_part) - Kratos.Expression.VariableExpressionIO.Read(cls.x_exp, Kratos.PRESSURE, False) - cls.x = cls.x_exp.Evaluate() - cls.clamper = KratosSI.NodeSmoothClamper(-10, 10) + cls.x_ta = Kratos.TensorAdaptors.VariableTensorAdaptor(cls.model_part.Nodes, Kratos.PRESSURE) + cls.x_ta.Check() + cls.x_ta.CollectData() + cls.clamper = KratosSI.SmoothClamper(-10, 10) def test_Clamp(self) -> None: - y = self.clamper.ProjectForward(self.x_exp).Evaluate() - for i, y_i in enumerate(y): - if self.x[i] < -10.0: + y = self.clamper.ProjectForward(self.x_ta) + for i, y_i in enumerate(y.data): + if self.x_ta.data[i] < -10.0: self.assertEqual(y_i, -10.0) - elif self.x[i] > 10.0: + elif self.x_ta.data[i] > 10.0: self.assertEqual(y_i, 10.0) - self.assertAlmostEqual(np.linalg.norm(y), 98.78158380993898) + self.assertAlmostEqual(np.linalg.norm(y.data), 98.78158380993898) def test_InverseClamp(self) -> None: - y = self.clamper.ProjectForward(self.x_exp) - x = self.clamper.ProjectBackward(y).Evaluate() + y = self.clamper.ProjectForward(self.x_ta) + x = self.clamper.ProjectBackward(y) - x_clamped = np.clip(self.x_exp.Evaluate(), -10, 10) - self.assertAlmostEqual(np.linalg.norm(x - x_clamped), 0.0) + x_clamped = np.clip(self.x_ta.data, -10, 10) + self.assertAlmostEqual(np.linalg.norm(x.data - x_clamped), 0.0) def test_ClampDerivative(self) -> None: delta = 1e-8 - y_ref = self.clamper.ProjectForward(self.x_exp).Evaluate() - y = self.clamper.ProjectForward(self.x_exp + delta).Evaluate() - dy_dx = self.clamper.CalculateForwardProjectionGradient(self.x_exp).Evaluate() + y_ref = self.clamper.ProjectForward(self.x_ta) - for i, dy_dx in enumerate(dy_dx): - self.assertAlmostEqual(dy_dx, (y[i] - y_ref[i]) / delta, 5) + perturbed_x_ta = self.x_ta.Clone() + perturbed_x_ta.data[:] += delta + y = self.clamper.ProjectForward(perturbed_x_ta) + dy_dx = self.clamper.CalculateForwardProjectionGradient(self.x_ta) + + for i, dy_dx in enumerate(dy_dx.data): + self.assertAlmostEqual(dy_dx, (y.data[i] - y_ref.data[i]) / delta, 5) if __name__ == '__main__': UnitTest.main() \ No newline at end of file From 432412e5f1999ad1284ce97b71e8ef66508009fc Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Tue, 17 Feb 2026 10:19:16 +0100 Subject: [PATCH 091/116] update sensor and sensorview --- .../add_custom_sensors_to_python.cpp | 51 ++++---------- .../add_custom_utilities_to_python.cpp | 1 - .../custom_sensors/sensor.cpp | 32 ++++----- .../custom_sensors/sensor.h | 44 ++++++------ .../custom_sensors/sensor_view.cpp | 68 +++++++------------ .../custom_sensors/sensor_view.h | 22 +++--- .../custom_utilities/sensor_utils.cpp | 21 ------ .../custom_utilities/sensor_utils.h | 17 +---- 8 files changed, 82 insertions(+), 174 deletions(-) diff --git a/applications/SystemIdentificationApplication/custom_python/add_custom_sensors_to_python.cpp b/applications/SystemIdentificationApplication/custom_python/add_custom_sensors_to_python.cpp index f06f1f75e960..f5a68a5a4608 100644 --- a/applications/SystemIdentificationApplication/custom_python/add_custom_sensors_to_python.cpp +++ b/applications/SystemIdentificationApplication/custom_python/add_custom_sensors_to_python.cpp @@ -42,47 +42,22 @@ void AddCustomSensorsToPython(pybind11::module& m) .def("GetSensorValue", &Sensor::GetSensorValue) .def("SetSensorValue", &Sensor::SetSensorValue) .def("GetSensorParameters", &Sensor::GetSensorParameters) - .def("AddContainerExpression", &Sensor::AddContainerExpression, py::arg("expression_name"), py::arg("expression")) - .def("GetContainerExpression", &Sensor::GetContainerExpression, py::arg("expression_name")) - .def("GetContainerExpressionsMap", &Sensor::GetContainerExpressionsMap) - .def("ClearContainerExpressions", &Sensor::ClearContainerExpressions) + .def("AddTensorAdaptor", &Sensor::AddTensorAdaptor, py::arg("tensor_adaptor_name"), py::arg("tensor_adaptor")) + .def("GetTensorAdaptor", &Sensor::GetTensorAdaptor, py::arg("tensor_adaptor_name")) + .def("GetTensorAdaptorsMap", &Sensor::GetTensorAdaptorsMap) + .def("ClearTensorAdaptors", &Sensor::ClearTensorAdaptors) .def("__str__", PrintObject); ; - using nodal_sensor_view = SensorView; - py::class_(sensor_module, "NodalSensorView") - .def(py::init(), py::arg("sensor"), py::arg("expression_name")) - .def("GetSensor", &nodal_sensor_view::GetSensor) - .def("GetContainerExpression", &nodal_sensor_view::GetContainerExpression) - .def("GetExpressionName", &nodal_sensor_view::GetExpressionName) - .def("AddAuxiliaryExpression", &nodal_sensor_view::AddAuxiliaryExpression, py::arg("suffix"), py::arg("nodal_expression")) - .def("GetAuxiliaryExpression", &nodal_sensor_view::GetAuxiliaryExpression, py::arg("suffix")) - .def("GetAuxiliarySuffixes", &nodal_sensor_view::GetAuxiliarySuffixes) - .def("__str__", PrintObject); - ; - - using condition_sensor_view = SensorView; - py::class_(sensor_module, "ConditionSensorView") - .def(py::init(), py::arg("sensor"), py::arg("expression_name")) - .def("GetSensor", &condition_sensor_view::GetSensor) - .def("GetContainerExpression", &condition_sensor_view::GetContainerExpression) - .def("GetExpressionName", &condition_sensor_view::GetExpressionName) - .def("AddAuxiliaryExpression", &condition_sensor_view::AddAuxiliaryExpression, py::arg("suffix"), py::arg("condition_expression")) - .def("GetAuxiliaryExpression", &condition_sensor_view::GetAuxiliaryExpression, py::arg("suffix")) - .def("GetAuxiliarySuffixes", &condition_sensor_view::GetAuxiliarySuffixes) - .def("__str__", PrintObject); - ; - - using element_sensor_view = SensorView; - py::class_(sensor_module, "ElementSensorView") - .def(py::init(), py::arg("sensor"), py::arg("expression_name")) - .def("GetSensor", &element_sensor_view::GetSensor) - .def("GetContainerExpression", &element_sensor_view::GetContainerExpression) - .def("GetExpressionName", &element_sensor_view::GetExpressionName) - .def("AddAuxiliaryExpression", &element_sensor_view::AddAuxiliaryExpression, py::arg("suffix"), py::arg("element_expression")) - .def("GetAuxiliaryExpression", &element_sensor_view::GetAuxiliaryExpression, py::arg("suffix")) - .def("GetAuxiliarySuffixes", &element_sensor_view::GetAuxiliarySuffixes) - .def("__str__", PrintObject); + py::class_(sensor_module, "SensorView") + .def(py::init(), py::arg("sensor"), py::arg("tensor_adaptor_name")) + .def("GetSensor", &SensorView::GetSensor) + .def("GetTensorAdaptor", &SensorView::GetTensorAdaptor) + .def("GetTensorAdaptorName", &SensorView::GetTensorAdaptorName) + .def("AddAuxiliaryTensorAdaptor", &SensorView::AddAuxiliaryTensorAdaptor, py::arg("suffix"), py::arg("tensor_adaptor")) + .def("GetAuxiliaryTensorAdaptor", &SensorView::GetAuxiliaryTensorAdaptor, py::arg("suffix")) + .def("GetAuxiliarySuffixes", &SensorView::GetAuxiliarySuffixes) + .def("__str__", PrintObject); ; py::class_(sensor_module, "DisplacementSensor") diff --git a/applications/SystemIdentificationApplication/custom_python/add_custom_utilities_to_python.cpp b/applications/SystemIdentificationApplication/custom_python/add_custom_utilities_to_python.cpp index 3ee4f8c44d28..34b0fb8c7444 100644 --- a/applications/SystemIdentificationApplication/custom_python/add_custom_utilities_to_python.cpp +++ b/applications/SystemIdentificationApplication/custom_python/add_custom_utilities_to_python.cpp @@ -82,7 +82,6 @@ void AddCustomUtilitiesToPython(pybind11::module& m) auto sensor_utils = m.def_submodule("SensorUtils"); sensor_utils.def("IsPointInGeometry", &SensorUtils::IsPointInGeometry, py::arg("point"), py::arg("geometry")); - sensor_utils.def("CreateSensorView", &SensorUtils::CreateSensorView, py::arg("sensor"), py::arg("expression_name")); py::class_(m, "DistanceMatrix") .def(py::init<>()) diff --git a/applications/SystemIdentificationApplication/custom_sensors/sensor.cpp b/applications/SystemIdentificationApplication/custom_sensors/sensor.cpp index cfa8f23ac8ac..8c8f0c40ed7e 100644 --- a/applications/SystemIdentificationApplication/custom_sensors/sensor.cpp +++ b/applications/SystemIdentificationApplication/custom_sensors/sensor.cpp @@ -110,31 +110,31 @@ void Sensor::SetSensorValue(const double Value) mSensorValue = Value; } -void Sensor::AddContainerExpression( - const std::string& rExpressionName, - ContainerExpressionType pContainerExpression) +void Sensor::AddTensorAdaptor( + const std::string& rTensorAdaptorName, + TensorAdaptor::Pointer pTensorAdaptor) { KRATOS_TRY - const auto p_itr = mContainerExpressions.find(rExpressionName); - KRATOS_ERROR_IF_NOT(p_itr == mContainerExpressions.end()) - << "A container expression named \"" << rExpressionName << " already exists."; - mContainerExpressions[rExpressionName] = pContainerExpression; + const auto p_itr = mTensorAdaptorsMap.find(rTensorAdaptorName); + KRATOS_ERROR_IF_NOT(p_itr == mTensorAdaptorsMap.end()) + << "A tensor adaptor named \"" << rTensorAdaptorName << " already exists."; + mTensorAdaptorsMap[rTensorAdaptorName] = pTensorAdaptor; KRATOS_CATCH(""); } -Sensor::ContainerExpressionType Sensor::GetContainerExpression(const std::string& rExpressionName) const +TensorAdaptor::Pointer Sensor::GetTensorAdaptor(const std::string& rTensorAdaptorName) const { KRATOS_TRY - const auto p_itr = mContainerExpressions.find(rExpressionName); + const auto p_itr = mTensorAdaptorsMap.find(rTensorAdaptorName); - if (p_itr == mContainerExpressions.end()) { + if (p_itr == mTensorAdaptorsMap.end()) { std::stringstream msg; - msg << "A container expression named \"" << rExpressionName << "\" not found in " + msg << "A tensor adaptor named \"" << rTensorAdaptorName << "\" not found in " << "sensor named \"" << this->GetName() << "\". Followings are available:"; - for (const auto& r_pair : this->GetContainerExpressionsMap()) { + for (const auto& r_pair : this->GetTensorAdaptorsMap()) { msg << std::endl << " " << r_pair.first; } KRATOS_ERROR << msg.str(); @@ -145,14 +145,14 @@ Sensor::ContainerExpressionType Sensor::GetContainerExpression(const std::string KRATOS_CATCH(""); } -std::unordered_map Sensor::GetContainerExpressionsMap() const +std::unordered_map::Pointer> Sensor::GetTensorAdaptorsMap() const { - return mContainerExpressions; + return mTensorAdaptorsMap; } -void Sensor::ClearContainerExpressions() +void Sensor::ClearTensorAdaptors() { - mContainerExpressions.clear(); + mTensorAdaptorsMap.clear(); } std::string Sensor::Info() const diff --git a/applications/SystemIdentificationApplication/custom_sensors/sensor.h b/applications/SystemIdentificationApplication/custom_sensors/sensor.h index 88cd08533220..c07b56ba40c4 100644 --- a/applications/SystemIdentificationApplication/custom_sensors/sensor.h +++ b/applications/SystemIdentificationApplication/custom_sensors/sensor.h @@ -19,7 +19,7 @@ // Project includes #include "containers/array_1d.h" #include "containers/data_value_container.h" -#include "expression/container_expression.h" +#include "tensor_adaptors/tensor_adaptor.h" #include "geometries/point.h" #include "includes/define.h" #include "includes/kratos_parameters.h" @@ -41,12 +41,6 @@ class KRATOS_API(SYSTEM_IDENTIFICATION_APPLICATION) Sensor: public AdjointRespon KRATOS_CLASS_POINTER_DEFINITION(Sensor); - using ContainerExpressionType = std::variant< - ContainerExpression::Pointer, - ContainerExpression::Pointer, - ContainerExpression::Pointer - >; - ///@} ///@name Life Cycle ///@{ @@ -158,39 +152,39 @@ class KRATOS_API(SYSTEM_IDENTIFICATION_APPLICATION) Sensor: public AdjointRespon void SetSensorValue(const double Value); /** - * @brief Adds given container expression + * @brief Adds given tensor adaptor * - * @throws If an expression is found already under the given name. + * @throws If an tensor adaptor is found already under the given name. * - * @param rExpressionName Name of the container expression. - * @param pContainerExpression Container expression pointer to be added. + * @param rTensorAdaptorName Name of the tensor adaptor. + * @param pTensorAdaptor Tensor adaptor pointer to be added. */ - void AddContainerExpression( - const std::string& rExpressionName, - ContainerExpressionType pContainerExpression); + void AddTensorAdaptor( + const std::string& rTensorAdaptorName, + TensorAdaptor::Pointer pTensorAdaptor); /** - * @brief Get the Nodal Expression for specified expression name + * @brief Get the tensor adaptor for specified tensor adaptor name * - * @throws If the @ref rExpressionName is not found in the map of container expressions. + * @throws If the @ref rTensorAdaptorName is not found in the map of tensor adaptors. * - * @param rExpressionName Expression name - * @return ContainerExpressionType Container expression + * @param rTensorAdaptorName Tensor adaptor name + * @return TensorAdaptor::Pointer Tensor adaptor */ - ContainerExpressionType GetContainerExpression(const std::string& rExpressionName) const; + TensorAdaptor::Pointer GetTensorAdaptor(const std::string& rTensorAdaptorName) const; /** - * @brief Get the Container Expressions map + * @brief Get the tensor adaptors map * - * @return std::unordered_map Container expressions map + * @return std::unordered_map::Pointer> Tensor adaptors map */ - std::unordered_map GetContainerExpressionsMap() const; + std::unordered_map::Pointer> GetTensorAdaptorsMap() const; /** - * @brief Clear container expressions from the sensors. + * @brief Clear tensor adaptors from the sensors. * */ - void ClearContainerExpressions(); + void ClearTensorAdaptors(); ///@} ///@name Input and output @@ -216,7 +210,7 @@ class KRATOS_API(SYSTEM_IDENTIFICATION_APPLICATION) Sensor: public AdjointRespon double mSensorValue; - std::unordered_map mContainerExpressions; + std::unordered_map::Pointer> mTensorAdaptorsMap; ///@} }; diff --git a/applications/SystemIdentificationApplication/custom_sensors/sensor_view.cpp b/applications/SystemIdentificationApplication/custom_sensors/sensor_view.cpp index c0f01ec85f62..d8f93328ad63 100644 --- a/applications/SystemIdentificationApplication/custom_sensors/sensor_view.cpp +++ b/applications/SystemIdentificationApplication/custom_sensors/sensor_view.cpp @@ -25,69 +25,55 @@ namespace Kratos { -template -SensorView::SensorView( +SensorView::SensorView( Sensor::Pointer pSensor, - const std::string& rExpressionName) + const std::string& rTensorAdaptorName) : mpSensor(pSensor), - mExpressionName(rExpressionName) + mTensorAdaptorName(rTensorAdaptorName), + mpTensorAdaptor(pSensor->GetTensorAdaptor(rTensorAdaptorName)) { - KRATOS_TRY - - auto p_expression = pSensor->GetContainerExpression(rExpressionName); - this->mpContainerExpression = std::get::Pointer>(p_expression); - - KRATOS_CATCH(""); } -template -Sensor::Pointer SensorView::GetSensor() const +Sensor::Pointer SensorView::GetSensor() const { return mpSensor; } -template -typename ContainerExpression::Pointer SensorView::GetContainerExpression() const +TensorAdaptor::Pointer SensorView::GetTensorAdaptor() const { - return mpContainerExpression; + return mpTensorAdaptor; } -template -std::string SensorView::GetExpressionName() const +std::string SensorView::GetTensorAdaptorName() const { - return mExpressionName; + return mTensorAdaptorName; } -template -void SensorView::AddAuxiliaryExpression( +void SensorView::AddAuxiliaryTensorAdaptor( const std::string& rSuffix, - typename ContainerExpression::Pointer pContainerExpression) + TensorAdaptor::Pointer pTensorAdaptor) { std::stringstream name; - name << this->mExpressionName << "_" << rSuffix; - mpSensor->AddContainerExpression(name.str(), pContainerExpression); + name << this->mTensorAdaptorName << "_" << rSuffix; + mpSensor->AddTensorAdaptor(name.str(), pTensorAdaptor); } -template -typename ContainerExpression::Pointer SensorView::GetAuxiliaryExpression(const std::string& rSuffix) const +TensorAdaptor::Pointer SensorView::GetAuxiliaryTensorAdaptor(const std::string& rSuffix) const { std::stringstream name; - name << this->mExpressionName << "_" << rSuffix; - - auto p_expression = mpSensor->GetContainerExpression(name.str()); - return std::get::Pointer>(p_expression); + name << this->mTensorAdaptorName << "_" << rSuffix; + return mpSensor->GetTensorAdaptor(name.str()); } -template -std::vector SensorView::GetAuxiliarySuffixes() const +std::vector SensorView::GetAuxiliarySuffixes() const { KRATOS_TRY std::vector suffixes; - for (const auto& r_pair : mpSensor->GetContainerExpressionsMap()) { + for (const auto& r_pair : mpSensor->GetTensorAdaptorsMap()) { const auto& r_name = r_pair.first; - if (r_name.rfind(mExpressionName + "_", 0) == 0) { - suffixes.push_back(r_name.substr(mExpressionName.size() + 1)); + if (r_name.rfind(mTensorAdaptorName + "_", 0) == 0) { + suffixes.push_back(r_name.substr(mTensorAdaptorName.size() + 1)); } } @@ -96,27 +82,19 @@ std::vector SensorView::GetAuxiliarySuffixes() cons KRATOS_CATCH(""); } -template -std::string SensorView::Info() const +std::string SensorView::Info() const { return mpSensor->Info(); } -template -void SensorView::PrintInfo(std::ostream& rOStream) const +void SensorView::PrintInfo(std::ostream& rOStream) const { mpSensor->PrintInfo(rOStream); } -template -void SensorView::PrintData(std::ostream& rOStream) const +void SensorView::PrintData(std::ostream& rOStream) const { mpSensor->PrintData(rOStream); } -// template instantiations -template class SensorView; -template class SensorView; -template class SensorView; - } /* namespace Kratos.*/ \ No newline at end of file diff --git a/applications/SystemIdentificationApplication/custom_sensors/sensor_view.h b/applications/SystemIdentificationApplication/custom_sensors/sensor_view.h index b44fd42fe96c..b531152fc0c8 100644 --- a/applications/SystemIdentificationApplication/custom_sensors/sensor_view.h +++ b/applications/SystemIdentificationApplication/custom_sensors/sensor_view.h @@ -18,7 +18,7 @@ // External includes // Project includes -#include "expression/container_expression.h" +#include "tensor_adaptors/tensor_adaptor.h" #include "includes/define.h" // Application includes @@ -28,7 +28,6 @@ namespace Kratos { ///@name Kratos Classes ///@{ -template class KRATOS_API(SYSTEM_IDENTIFICATION_APPLICATION) SensorView { public: @@ -44,7 +43,7 @@ class KRATOS_API(SYSTEM_IDENTIFICATION_APPLICATION) SensorView /// Constructor. SensorView( Sensor::Pointer pSensor, - const std::string& rExpressionName); + const std::string& rTensorAdaptorName); ///@} ///@name Public operations @@ -52,15 +51,15 @@ class KRATOS_API(SYSTEM_IDENTIFICATION_APPLICATION) SensorView Sensor::Pointer GetSensor() const; - typename ContainerExpression::Pointer GetContainerExpression() const; + TensorAdaptor::Pointer GetTensorAdaptor() const; - std::string GetExpressionName() const; + std::string GetTensorAdaptorName() const; - void AddAuxiliaryExpression( + void AddAuxiliaryTensorAdaptor( const std::string& rSuffix, - typename ContainerExpression::Pointer pContainerExpression); + TensorAdaptor::Pointer pTensorAdaptor); - typename ContainerExpression::Pointer GetAuxiliaryExpression(const std::string& rSuffix) const; + TensorAdaptor::Pointer GetAuxiliaryTensorAdaptor(const std::string& rSuffix) const; std::vector GetAuxiliarySuffixes() const; @@ -82,18 +81,17 @@ class KRATOS_API(SYSTEM_IDENTIFICATION_APPLICATION) SensorView Sensor::Pointer mpSensor; - const std::string mExpressionName; + const std::string mTensorAdaptorName; - typename ContainerExpression::Pointer mpContainerExpression; + TensorAdaptor::Pointer mpTensorAdaptor; ///@} }; /// output stream functions -template inline std::ostream& operator<<( std::ostream& rOStream, - const SensorView& rThis) + const SensorView& rThis) { rThis.PrintInfo(rOStream); rOStream << std::endl; diff --git a/applications/SystemIdentificationApplication/custom_utilities/sensor_utils.cpp b/applications/SystemIdentificationApplication/custom_utilities/sensor_utils.cpp index 212e0de856c4..8906b2c22291 100644 --- a/applications/SystemIdentificationApplication/custom_utilities/sensor_utils.cpp +++ b/applications/SystemIdentificationApplication/custom_utilities/sensor_utils.cpp @@ -31,27 +31,6 @@ bool SensorUtils::IsPointInGeometry( return rGeometry.IsInside(rPoint, result); } -SensorUtils::SensorViewType SensorUtils::CreateSensorView( - Sensor::Pointer pSensor, - const std::string& rExpressionName) -{ - KRATOS_TRY - - auto p_expression = pSensor->GetContainerExpression(rExpressionName); - if (std::holds_alternative::Pointer>(p_expression)) { - return std::make_shared>(pSensor, rExpressionName); - } else if (std::holds_alternative::Pointer>(p_expression)) { - return std::make_shared>(pSensor, rExpressionName); - } else if (std::holds_alternative::Pointer>(p_expression)) { - return std::make_shared>(pSensor, rExpressionName); - } else { - KRATOS_ERROR << "Unsupported expression type."; - return std::make_shared>(pSensor, rExpressionName); - } - - KRATOS_CATCH(""); -} - void SensorUtils::ReadVariableData( DataValueContainer& rDataValueContainer, Parameters VariableDataParameters) diff --git a/applications/SystemIdentificationApplication/custom_utilities/sensor_utils.h b/applications/SystemIdentificationApplication/custom_utilities/sensor_utils.h index d5d351300369..23a617a0db7c 100644 --- a/applications/SystemIdentificationApplication/custom_utilities/sensor_utils.h +++ b/applications/SystemIdentificationApplication/custom_utilities/sensor_utils.h @@ -18,10 +18,10 @@ // Project includes #include "includes/node.h" +#include "includes/kratos_parameters.h" #include "geometries/geometry.h" // Application includes -#include "custom_sensors/sensor_view.h" namespace Kratos { ///@name Kratos Classes @@ -30,17 +30,6 @@ namespace Kratos { class KRATOS_API(SYSTEM_IDENTIFICATION_APPLICATION) SensorUtils { public: - ///@name Type definitions - ///@{ - - using SensorViewType = std::variant< - SensorView::Pointer, - SensorView::Pointer, - SensorView::Pointer - >; - - - ///@} ///@name Public static operations ///@{ @@ -48,10 +37,6 @@ class KRATOS_API(SYSTEM_IDENTIFICATION_APPLICATION) SensorUtils const Point& rPoint, const Geometry& rGeometry); - static SensorViewType CreateSensorView( - Sensor::Pointer pSensor, - const std::string& rExpressionName); - static void ReadVariableData( DataValueContainer& rDataValueContainer, Parameters VariableDataParameters); From 9a93ed74f43026259d79f668b05eb692da001ef8 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Tue, 17 Feb 2026 11:47:31 +0100 Subject: [PATCH 092/116] update mask utils to TA --- .../add_custom_utilities_to_python.cpp | 42 +-- .../custom_utilities/mask_utils.cpp | 333 +++++++----------- .../custom_utilities/mask_utils.h | 123 +++---- .../tests/test_mask_utils.py | 99 +++--- 4 files changed, 243 insertions(+), 354 deletions(-) diff --git a/applications/SystemIdentificationApplication/custom_python/add_custom_utilities_to_python.cpp b/applications/SystemIdentificationApplication/custom_python/add_custom_utilities_to_python.cpp index 34b0fb8c7444..506cbaf0fd88 100644 --- a/applications/SystemIdentificationApplication/custom_python/add_custom_utilities_to_python.cpp +++ b/applications/SystemIdentificationApplication/custom_python/add_custom_utilities_to_python.cpp @@ -31,35 +31,6 @@ namespace Kratos::Python { -template -void AddMaskUtilsToPython(pybind11::module& m) -{ - namespace py = pybind11; - - std::string lower_prefix, upper_prefix; - if constexpr(std::is_same_v) { - lower_prefix = "nodal"; - upper_prefix = "Nodal"; - } else if constexpr(std::is_same_v) { - lower_prefix = "condition"; - upper_prefix = "Condition"; - } else if constexpr(std::is_same_v) { - lower_prefix = "element"; - upper_prefix = "Element"; - } - - m.def("GetMaskSize", &MaskUtils::GetMaskSize, py::arg((lower_prefix + "_mask_expression").c_str()), py::arg("required_minimum_redundancy") = 1); - m.def("GetMask", py::overload_cast&>(&MaskUtils::GetMask), py::arg((lower_prefix + "_scalar_expression").c_str())); - m.def("GetMask", py::overload_cast&, const double>(&MaskUtils::GetMask), py::arg((lower_prefix + "_scalar_expression").c_str()), py::arg("threshold")); - m.def("GetMaskThreshold", &MaskUtils::GetMaskThreshold, py::arg((lower_prefix + "_scalar_expression").c_str())); - m.def("Union", &MaskUtils::Union, py::arg((lower_prefix + "_mask_1_expression").c_str()), py::arg((lower_prefix + "_mask_2_expression").c_str()), py::arg("required_minimum_redundancy") = 1); - m.def("Intersect", &MaskUtils::Intersect, py::arg((lower_prefix + "_mask_1_expression").c_str()), py::arg((lower_prefix + "_mask_2_expression").c_str()), py::arg("required_minimum_redundancy") = 1); - m.def("Subtract", &MaskUtils::Subtract, py::arg((lower_prefix + "_mask_1_expression").c_str()), py::arg((lower_prefix + "_mask_2_expression").c_str()), py::arg("required_minimum_redundancy") = 1); - m.def("Scale", &MaskUtils::Scale, py::arg((lower_prefix + "_scalar_expression").c_str()), py::arg((lower_prefix + "_mask_expression").c_str()), py::arg("required_minimum_redundancy") = 1); - m.def("ClusterMasks", &MaskUtils::ClusterMasks, py::arg(("list_of_" + lower_prefix + "_mask_expressions").c_str()), py::arg("required_minimum_redundancy") = 1); - m.def("GetMasksDividingReferenceMask", &MaskUtils::GetMasksDividingReferenceMask, py::arg(("reference_" + lower_prefix + "_mask_expression").c_str()), py::arg(("list_of_" + lower_prefix + "_mask_expressions").c_str()), py::arg("required_minimum_redundancy") = 1); -} - void AddCustomUtilitiesToPython(pybind11::module& m) { namespace py = pybind11; @@ -76,9 +47,16 @@ void AddCustomUtilitiesToPython(pybind11::module& m) ; auto mask_utils = m.def_submodule("MaskUtils"); - AddMaskUtilsToPython(mask_utils); - AddMaskUtilsToPython(mask_utils); - AddMaskUtilsToPython(mask_utils); + mask_utils.def("GetMaskSize", &MaskUtils::GetMaskSize, py::arg("mask_tensor_adaptor"), py::arg("required_minimum_redundancy") = 1); + mask_utils.def("GetMask", py::overload_cast&>(&MaskUtils::GetMask), py::arg("scalar_tensor_adaptor")); + mask_utils.def("GetMask", py::overload_cast&, const double>(&MaskUtils::GetMask), py::arg("scalar_tensor_adaptor"), py::arg("threshold")); + mask_utils.def("GetMaskThreshold", &MaskUtils::GetMaskThreshold, py::arg("scalar_tensor_adaptor")); + mask_utils.def("Union", &MaskUtils::Union, py::arg("mask_1_tensor_adaptor"), py::arg("mask_2_tensor_adaptor"), py::arg("required_minimum_redundancy") = 1); + mask_utils.def("Intersect", &MaskUtils::Intersect, py::arg("mask_1_tensor_adaptor"), py::arg("mask_2_tensor_adaptor"), py::arg("required_minimum_redundancy") = 1); + mask_utils.def("Subtract", &MaskUtils::Subtract, py::arg("mask_1_tensor_adaptor"), py::arg("mask_2_tensor_adaptor"), py::arg("required_minimum_redundancy") = 1); + mask_utils.def("Scale", &MaskUtils::Scale, py::arg("scalar_tensor_adaptor"), py::arg("mask_tensor_adaptor"), py::arg("required_minimum_redundancy") = 1); + mask_utils.def("ClusterMasks", &MaskUtils::ClusterMasks, py::arg("list_of_mask_tensor_adaptors"), py::arg("required_minimum_redundancy") = 1); + mask_utils.def("GetMasksDividingReferenceMask", &MaskUtils::GetMasksDividingReferenceMask, py::arg("reference_mask_tensor_adaptor"), py::arg("list_of_mask_tensor_adaptors"), py::arg("required_minimum_redundancy") = 1); auto sensor_utils = m.def_submodule("SensorUtils"); sensor_utils.def("IsPointInGeometry", &SensorUtils::IsPointInGeometry, py::arg("point"), py::arg("geometry")); diff --git a/applications/SystemIdentificationApplication/custom_utilities/mask_utils.cpp b/applications/SystemIdentificationApplication/custom_utilities/mask_utils.cpp index 26efa6f3ce4d..91eae99be668 100644 --- a/applications/SystemIdentificationApplication/custom_utilities/mask_utils.cpp +++ b/applications/SystemIdentificationApplication/custom_utilities/mask_utils.cpp @@ -20,8 +20,6 @@ // Project includes #include "utilities/parallel_utilities.h" #include "utilities/reduction_utilities.h" -#include "expression/literal_expression.h" -#include "expression/literal_flat_expression.h" // Application includes @@ -30,60 +28,57 @@ namespace Kratos { -template void MaskUtils::CheckCompatibility( - const ContainerExpression& rMask1, - const ContainerExpression& rMask2) + const TensorAdaptor& rMask1, + const TensorAdaptor& rMask2) { KRATOS_TRY - KRATOS_ERROR_IF_NOT(rMask1.GetItemComponentCount() == 1) - << "rMask1 should be a scalar expression. [ shape of the given expression = " - << rMask1.GetItemShape() << " ].\n"; + KRATOS_ERROR_IF_NOT(rMask1.Shape().size() == 1) + << "rMask1 should be a scalar tensor adaptor. [ shape of the given tensor adaptor = " + << rMask1.Shape() << " ].\n"; - KRATOS_ERROR_IF_NOT(rMask2.GetItemComponentCount() == 1) - << "rMask2 should be a scalar expression. [ shape of the given expression = " - << rMask2.GetItemShape() << " ].\n"; + KRATOS_ERROR_IF_NOT(rMask2.Shape().size() == 1) + << "rMask2 should be a scalar tensor adaptor. [ shape of the given tensor adaptor = " + << rMask2.Shape() << " ].\n"; - KRATOS_ERROR_IF_NOT(rMask1.GetContainer().size() == rMask2.GetContainer().size()) - << "rMask1 and rMask2 entities size mismatch [ rMask1.size() = " << rMask1.GetContainer().size() - << ", rMask2.size() = " << rMask2.GetContainer().size() << " ].\n"; + KRATOS_ERROR_IF_NOT(rMask1.Size() == rMask2.Size()) + << "rMask1 and rMask2 entities size mismatch [ rMask1.size() = " << rMask1.Size() + << ", rMask2.size() = " << rMask2.Size() << " ].\n"; KRATOS_CATCH(""); } -template std::size_t MaskUtils::GetMaskSize( - const ContainerExpression& rMask, + const TensorAdaptor& rMask, const IndexType RequiredMinimumRedundancy) { KRATOS_TRY - KRATOS_ERROR_IF_NOT(rMask.GetItemComponentCount() == 1) - << "Mask should be a scalar expression. [ shape of the given expression = " - << rMask.GetItemShape() << " ].\n"; + KRATOS_ERROR_IF_NOT(rMask.Shape().size() == 1) + << "Mask should be a scalar tensor adaptor. [ shape of the given tensor adaptor = " + << rMask.Shape() << " ].\n"; - const auto& r_expression = rMask.GetExpression(); + const auto input_data_view = rMask.ViewData(); - return rMask.GetModelPart().GetCommunicator().GetDataCommunicator().SumAll(IndexPartition(r_expression.NumberOfEntities()).for_each>([&r_expression, RequiredMinimumRedundancy](const auto Index) { - return r_expression.Evaluate(Index, Index, 0) >= RequiredMinimumRedundancy; - })); + return IndexPartition(rMask.Size()).for_each>([&input_data_view, RequiredMinimumRedundancy](const auto Index) { + return input_data_view[Index] >= RequiredMinimumRedundancy; + }); KRATOS_CATCH(""); } -template -ContainerExpression MaskUtils::GetMask( - const ContainerExpression& rScalarExpression) +TensorAdaptor::Pointer MaskUtils::GetMask( + const TensorAdaptor& rScalarTensorAdaptor) { KRATOS_TRY - const auto& r_input_expression = rScalarExpression.GetExpression(); - const auto number_of_entities = r_input_expression.NumberOfEntities(); + const auto input_data_view = rScalarTensorAdaptor.ViewData(); + const auto number_of_entities = rScalarTensorAdaptor.Size(); - KRATOS_ERROR_IF_NOT(r_input_expression.GetItemComponentCount() == 1) - << "rScalarExpression should be a scalar expression. [ shape of the given expression = " - << r_input_expression.GetItemShape() << " ].\n"; + KRATOS_ERROR_IF_NOT(rScalarTensorAdaptor.Shape().size() == 1) + << "rScalarTensorAdaptor should be a scalar tensor adaptor. [ shape of the given tensor adaptor = " + << rScalarTensorAdaptor.Shape() << " ].\n"; struct Data { @@ -95,12 +90,12 @@ ContainerExpression MaskUtils::GetMask( std::vector index_value_pairs_vector; index_value_pairs_vector.resize(number_of_entities); - IndexPartition(number_of_entities).for_each([&index_value_pairs_vector, &r_input_expression](const auto Index) { + IndexPartition(number_of_entities).for_each([&index_value_pairs_vector, &input_data_view](const auto Index) { index_value_pairs_vector[Index].mIndex = Index; - index_value_pairs_vector[Index].mValue = r_input_expression.Evaluate(Index, Index, 0); + index_value_pairs_vector[Index].mValue = input_data_view[Index]; }); - // now sort expression values + // now sort tensor adaptor values std::sort(index_value_pairs_vector.begin(), index_value_pairs_vector.end(), [](const auto& rV1, const auto& rV2){ return rV1.mValue > rV2.mValue; }); @@ -113,32 +108,31 @@ ContainerExpression MaskUtils::GetMask( return Data{Index, current_sum / std::sqrt(Index + 1)}; }); - auto p_expression = LiteralFlatExpression::Create(number_of_entities, {}); - IndexPartition(number_of_entities).for_each([&p_expression](const auto Index) { - *(p_expression->begin() + Index) = 0; + auto p_result = rScalarTensorAdaptor.Clone(); + auto p_result_data_view = p_result->ViewData(); + + IndexPartition(number_of_entities).for_each([&p_result_data_view](const auto Index) { + p_result_data_view[Index] = 0; }); - IndexPartition(r_data.mIndex + 1).for_each([&p_expression, &index_value_pairs_vector](const auto Index){ - *(p_expression->begin() + index_value_pairs_vector[Index].mIndex) = 1; + IndexPartition(r_data.mIndex + 1).for_each([&p_result_data_view, &index_value_pairs_vector](const auto Index){ + p_result_data_view[index_value_pairs_vector[Index].mIndex] = 1; }); - auto result = rScalarExpression; - result.SetExpression(p_expression); - return result; + return p_result; KRATOS_CATCH(""); } -template -double MaskUtils::GetMaskThreshold(const ContainerExpression& rScalarExpression) +double MaskUtils::GetMaskThreshold(const TensorAdaptor& rScalarTensorAdaptor) { KRATOS_TRY - const auto& r_input_expression = rScalarExpression.GetExpression(); - const auto number_of_entities = r_input_expression.NumberOfEntities(); + const auto input_data_view = rScalarTensorAdaptor.ViewData(); + const auto number_of_entities = rScalarTensorAdaptor.Size(); - KRATOS_ERROR_IF_NOT(r_input_expression.GetItemComponentCount() == 1) - << "rScalarExpression should be a scalar expression. [ shape of the given expression = " - << r_input_expression.GetItemShape() << " ].\n"; + KRATOS_ERROR_IF_NOT(rScalarTensorAdaptor.Shape().size() == 1) + << "rScalarTensorAdaptor should be a scalar tensor adaptor. [ shape of the given tensor adaptor = " + << rScalarTensorAdaptor.Shape() << " ].\n"; struct Data { @@ -150,12 +144,12 @@ double MaskUtils::GetMaskThreshold(const ContainerExpression& rS std::vector index_value_pairs_vector; index_value_pairs_vector.resize(number_of_entities); - IndexPartition(number_of_entities).for_each([&index_value_pairs_vector, &r_input_expression](const auto Index) { + IndexPartition(number_of_entities).for_each([&index_value_pairs_vector, &input_data_view](const auto Index) { index_value_pairs_vector[Index].mIndex = Index; - index_value_pairs_vector[Index].mValue = r_input_expression.Evaluate(Index, Index, 0); + index_value_pairs_vector[Index].mValue = input_data_view[Index]; }); - // now sort expression values + // now sort tensor adaptor values std::sort(index_value_pairs_vector.begin(), index_value_pairs_vector.end(), [](const auto& rV1, const auto& rV2){ return rV1.mValue > rV2.mValue; }); @@ -171,194 +165,184 @@ double MaskUtils::GetMaskThreshold(const ContainerExpression& rS if (r_data.mIndex < number_of_entities - 1) { const auto threshold_value_index_1 = index_value_pairs_vector[r_data.mIndex].mIndex; const auto threshold_value_index_2 = index_value_pairs_vector[r_data.mIndex + 1].mIndex; - return 0.5 * (r_input_expression.Evaluate(threshold_value_index_1, threshold_value_index_1, 0) + r_input_expression.Evaluate(threshold_value_index_2, threshold_value_index_2, 0)); + return 0.5 * (input_data_view[threshold_value_index_1] + input_data_view[threshold_value_index_2]); } else { const auto threshold_value_index = index_value_pairs_vector[r_data.mIndex].mIndex; - return r_input_expression.Evaluate(threshold_value_index, threshold_value_index, 0); + return input_data_view[threshold_value_index]; } KRATOS_CATCH(""); } -template -ContainerExpression MaskUtils::GetMask( - const ContainerExpression& rScalarExpression, +TensorAdaptor::Pointer MaskUtils::GetMask( + const TensorAdaptor& rScalarTensorAdaptor, const double Threshold) { KRATOS_TRY - const auto& r_input_expression = rScalarExpression.GetExpression(); - const auto number_of_entities = r_input_expression.NumberOfEntities(); + const auto input_data_view = rScalarTensorAdaptor.ViewData(); + const auto number_of_entities = input_data_view.size(); + + KRATOS_ERROR_IF_NOT(rScalarTensorAdaptor.Shape().size() == 1) + << "rScalarTensorAdaptor should be a scalar tensor adaptor. [ shape of the given tensor adaptor = " + << rScalarTensorAdaptor.Shape() << " ].\n"; - KRATOS_ERROR_IF_NOT(r_input_expression.GetItemComponentCount() == 1) - << "rScalarExpression should be a scalar expression. [ shape of the given expression = " - << r_input_expression.GetItemShape() << " ].\n"; + auto p_result = rScalarTensorAdaptor.Clone(); + auto output_data_view = p_result->ViewData(); - auto p_expression = LiteralFlatExpression::Create(number_of_entities, {}); - IndexPartition(number_of_entities).for_each([&p_expression, &r_input_expression, Threshold](const auto Index) { - *(p_expression->begin() + Index) = r_input_expression.Evaluate(Index, Index, 0) > Threshold; + IndexPartition(number_of_entities).for_each([&output_data_view, &input_data_view, Threshold](const auto Index) { + output_data_view[Index] = input_data_view[Index] > Threshold; }); - auto result = rScalarExpression; - result.SetExpression(p_expression); - return result; + return p_result; KRATOS_CATCH(""); } -template -ContainerExpression MaskUtils::Union( - const ContainerExpression& rMask1, - const ContainerExpression& rMask2, +TensorAdaptor::Pointer MaskUtils::Union( + const TensorAdaptor& rMask1, + const TensorAdaptor& rMask2, const IndexType RequiredMinimumRedundancy) { KRATOS_TRY CheckCompatibility(rMask1, rMask2); - const auto& r_mask_1_exp = rMask1.GetExpression(); - const auto& r_mask_2_exp = rMask2.GetExpression(); - const auto number_of_entities = r_mask_1_exp.NumberOfEntities(); + const auto& r_mask_1_data_view = rMask1.ViewData(); + const auto& r_mask_2_data_view = rMask2.ViewData(); + const auto number_of_entities = r_mask_1_data_view.size(); - auto p_expression = LiteralFlatExpression::Create(number_of_entities, {}); - IndexPartition(number_of_entities).for_each([&p_expression, &r_mask_1_exp, &r_mask_2_exp, RequiredMinimumRedundancy](const auto Index) { - *(p_expression->begin() + Index) = (r_mask_1_exp.Evaluate(Index, Index, 0) >= RequiredMinimumRedundancy || - r_mask_2_exp.Evaluate(Index, Index, 0) >= RequiredMinimumRedundancy) + auto p_result = rMask1.Clone(); + auto output_data_view = p_result->ViewData(); + IndexPartition(number_of_entities).for_each([&output_data_view, &r_mask_1_data_view, &r_mask_2_data_view, RequiredMinimumRedundancy](const auto Index) { + output_data_view[Index] = (r_mask_1_data_view[Index] >= RequiredMinimumRedundancy || + r_mask_2_data_view[Index] >= RequiredMinimumRedundancy) ? RequiredMinimumRedundancy : 0; }); - auto result = rMask1; - result.SetExpression(p_expression); - return result; + return p_result; KRATOS_CATCH(""); } -template -ContainerExpression MaskUtils::Intersect( - const ContainerExpression& rMask1, - const ContainerExpression& rMask2, +TensorAdaptor::Pointer MaskUtils::Intersect( + const TensorAdaptor& rMask1, + const TensorAdaptor& rMask2, const IndexType RequiredMinimumRedundancy) { KRATOS_TRY CheckCompatibility(rMask1, rMask2); - const auto& r_mask_1_exp = rMask1.GetExpression(); - const auto& r_mask_2_exp = rMask2.GetExpression(); - const auto number_of_entities = r_mask_1_exp.NumberOfEntities(); + const auto& r_mask_1_data_view = rMask1.ViewData(); + const auto& r_mask_2_data_view = rMask2.ViewData(); + const auto number_of_entities = r_mask_1_data_view.size(); - auto p_expression = LiteralFlatExpression::Create(number_of_entities, {}); - IndexPartition(number_of_entities).for_each([&p_expression, &r_mask_1_exp, &r_mask_2_exp, RequiredMinimumRedundancy](const auto Index) { - *(p_expression->begin() + Index) = (r_mask_1_exp.Evaluate(Index, Index, 0) >= RequiredMinimumRedundancy && - r_mask_2_exp.Evaluate(Index, Index, 0) >= RequiredMinimumRedundancy) + auto p_result = rMask1.Clone(); + auto output_data_view = p_result->ViewData(); + IndexPartition(number_of_entities).for_each([&output_data_view, &r_mask_1_data_view, &r_mask_2_data_view, RequiredMinimumRedundancy](const auto Index) { + output_data_view[Index] = (r_mask_1_data_view[Index] >= RequiredMinimumRedundancy && + r_mask_2_data_view[Index] >= RequiredMinimumRedundancy) ? RequiredMinimumRedundancy : 0; - }); + }); - auto result = rMask1; - result.SetExpression(p_expression); - return result; + return p_result; KRATOS_CATCH(""); } -template -ContainerExpression MaskUtils::Subtract( - const ContainerExpression& rMask1, - const ContainerExpression& rMask2, +TensorAdaptor::Pointer MaskUtils::Subtract( + const TensorAdaptor& rMask1, + const TensorAdaptor& rMask2, const IndexType RequiredMinimumRedundancy) { KRATOS_TRY CheckCompatibility(rMask1, rMask2); - const auto& r_mask_1_exp = rMask1.GetExpression(); - const auto& r_mask_2_exp = rMask2.GetExpression(); - const auto number_of_entities = r_mask_1_exp.NumberOfEntities(); + const auto& r_mask_1_data_view = rMask1.ViewData(); + const auto& r_mask_2_data_view = rMask2.ViewData(); + const auto number_of_entities = r_mask_1_data_view.size(); - auto p_expression = LiteralFlatExpression::Create(number_of_entities, {}); - IndexPartition(number_of_entities).for_each([&p_expression, &r_mask_1_exp, &r_mask_2_exp, RequiredMinimumRedundancy](const auto Index) { - *(p_expression->begin() + Index) = (r_mask_1_exp.Evaluate(Index, Index, 0) >= RequiredMinimumRedundancy && - r_mask_2_exp.Evaluate(Index, Index, 0) < RequiredMinimumRedundancy) + auto p_result = rMask1.Clone(); + auto output_data_view = p_result->ViewData(); + IndexPartition(number_of_entities).for_each([&output_data_view, &r_mask_1_data_view, &r_mask_2_data_view, RequiredMinimumRedundancy](const auto Index) { + output_data_view[Index] = (r_mask_1_data_view[Index] >= RequiredMinimumRedundancy && + r_mask_2_data_view[Index] < RequiredMinimumRedundancy) ? RequiredMinimumRedundancy : 0; }); - auto result = rMask1; - result.SetExpression(p_expression); - return result; + return p_result; KRATOS_CATCH(""); } -template -ContainerExpression MaskUtils::Scale( - const ContainerExpression& rScalarExpression, - const ContainerExpression& rMask, +TensorAdaptor::Pointer MaskUtils::Scale( + const TensorAdaptor& rScalarTensorAdaptor, + const TensorAdaptor& rMask, const IndexType RequiredMinimumRedundancy) { KRATOS_TRY - CheckCompatibility(rScalarExpression, rMask); + CheckCompatibility(rScalarTensorAdaptor, rMask); - const auto& r_scalar_expression = rScalarExpression.GetExpression(); - const auto& r_mask = rMask.GetExpression(); - const auto number_of_entities = r_scalar_expression.NumberOfEntities(); + const auto& input_data_view = rScalarTensorAdaptor.ViewData(); + const auto& mask_data_view = rMask.ViewData(); + const auto number_of_entities = input_data_view.size(); - auto p_expression = LiteralFlatExpression::Create(number_of_entities, {}); - IndexPartition(number_of_entities).for_each([&p_expression, &r_scalar_expression, &r_mask, RequiredMinimumRedundancy](const auto Index) { - *(p_expression->begin() + Index) = (r_mask.Evaluate(Index, Index, 0) >= RequiredMinimumRedundancy) - ? r_scalar_expression.Evaluate(Index, Index, 0) + auto p_result = rScalarTensorAdaptor.Clone(); + auto output_data_view = p_result->ViewData(); + IndexPartition(number_of_entities).for_each([&output_data_view, &input_data_view, &mask_data_view, RequiredMinimumRedundancy](const auto Index) { + output_data_view[Index] = (mask_data_view[Index] >= RequiredMinimumRedundancy) + ? input_data_view[Index] : 0; }); - auto result = rScalarExpression; - result.SetExpression(p_expression); - return result; + return p_result; KRATOS_CATCH(""); } -template -std::vector, typename ContainerExpression::Pointer>> MaskUtils::ClusterMasks( - const std::vector>& rMasksList, +std::vector, TensorAdaptor::Pointer>> MaskUtils::ClusterMasks( + const std::vector::Pointer>& rMasksList, const IndexType RequiredMinimumRedundancy) { KRATOS_TRY - std::vector, typename ContainerExpression::Pointer>> cluster_data; + std::vector, TensorAdaptor::Pointer>> cluster_data; if (rMasksList.size() == 0) { return cluster_data; } - const auto& r_front_cexp = rMasksList.front(); - const IndexType number_of_entities = r_front_cexp.GetExpression().NumberOfEntities(); + const auto& r_front_ta = rMasksList.front(); + const IndexType number_of_entities = r_front_ta->Size(); // Check if all the masks are compatible for (const auto& r_mask : rMasksList) { - KRATOS_ERROR_IF_NOT(number_of_entities == r_mask.GetExpression().NumberOfEntities()) + KRATOS_ERROR_IF_NOT(number_of_entities == r_mask->Size()) << "Mismatch in mask size [required mask size = " << number_of_entities << ", " - << " found one mask with size = " << r_mask.GetExpression().NumberOfEntities() << " ].\n"; + << " found one mask with size = " << r_mask->Size() << " ].\n"; - KRATOS_ERROR_IF_NOT(r_mask.GetExpression().GetItemComponentCount() == 1) - << "Found a mask with a non scalar dimensionality which is not allowed [ requried mask shape = {}, found shape = " - << r_mask.GetExpression().GetItemShape() << " ].\n"; + KRATOS_ERROR_IF_NOT(r_mask->Shape().size() == 1) + << "Found a mask with a non scalar dimensionality which is not allowed [ required mask shape = {}, found shape = " + << r_mask->Shape() << " ].\n"; } std::vector> domain_mask_indices(number_of_entities); IndexPartition(number_of_entities).for_each([&domain_mask_indices, &rMasksList, RequiredMinimumRedundancy](const auto Index) { auto& r_indices_list = domain_mask_indices[Index]; for (IndexType i = 0; i < rMasksList.size(); ++i) { - if (rMasksList[i].GetExpression().Evaluate(Index, Index, 0) >= RequiredMinimumRedundancy) { + if (rMasksList[i]->ViewData()[Index] >= RequiredMinimumRedundancy) { r_indices_list.push_back(i); } } }); // now find unique list of cluster indices - std::vector::Pointer> cluster_mask_exps; + std::vector::Pointer> cluster_mask_nd_data; for (IndexType i = 0; i < number_of_entities; ++i) { auto& mask_indices = domain_mask_indices[i]; std::sort(mask_indices.begin(), mask_indices.end()); @@ -366,25 +350,22 @@ std::vector, typename ContainerExpression(rData) == mask_indices; }); if (p_itr == cluster_data.end()) { - auto p_expression = LiteralFlatExpression::Create(number_of_entities, {}); - IndexPartition(number_of_entities).for_each([&p_expression](const auto Index){ - *(p_expression->begin() + Index) = 0; - }); - - auto p_container_exp = Kratos::make_shared>(*r_front_cexp.pGetModelPart()); - p_container_exp->SetExpression(p_expression); + auto p_nd_data = Kratos::make_shared>(Kratos::DenseVector(1, number_of_entities)); + auto p_nd_data_view = p_nd_data->ViewData(); + std::fill(p_nd_data_view.begin(), p_nd_data_view.end(), 0.0); + cluster_mask_nd_data.push_back(p_nd_data); - cluster_data.push_back(std::make_tuple(mask_indices, p_container_exp)); - cluster_mask_exps.push_back(p_expression); + auto p_cluster_ta = Kratos::make_shared>(r_front_ta->GetContainer(), p_nd_data, false); + cluster_data.push_back(std::make_tuple(mask_indices, p_cluster_ta)); } } // now fill in the cluster masks - IndexPartition(number_of_entities).for_each([&cluster_data, &domain_mask_indices, &cluster_mask_exps](const auto Index) { + IndexPartition(number_of_entities).for_each([&cluster_data, &domain_mask_indices, &cluster_mask_nd_data](const auto Index) { const auto& mask_indices = domain_mask_indices[Index]; auto p_itr = std::find_if(cluster_data.begin(), cluster_data.end(), [&mask_indices](const auto& rData){ return std::get<0>(rData) == mask_indices; }); const auto cluster_index = std::distance(cluster_data.begin(), p_itr); - *(cluster_mask_exps[cluster_index]->begin() + Index) = 1; + cluster_mask_nd_data[cluster_index]->ViewData()[Index] = 1; }); return cluster_data; @@ -392,10 +373,9 @@ std::vector, typename ContainerExpression std::vector MaskUtils::GetMasksDividingReferenceMask( - const ContainerExpression& rReferenceMask, - const std::vector::Pointer>& rMasksList, + const TensorAdaptor& rReferenceMask, + const std::vector::Pointer>& rMasksList, const IndexType RequiredMinimumRedundancy) { KRATOS_TRY @@ -404,10 +384,10 @@ std::vector MaskUtils::GetMasksDividingReferenceMask( std::vector indices; for (IndexType i = 0; i < rMasksList.size(); ++i) { - const auto& r_intersected_exp = Intersect(rReferenceMask, *rMasksList[i], RequiredMinimumRedundancy); - const auto intesection_coverage = GetMaskSize(r_intersected_exp, RequiredMinimumRedundancy); + const auto& p_intersected_ta = Intersect(rReferenceMask, *rMasksList[i], RequiredMinimumRedundancy); + const auto intersection_coverage = GetMaskSize(*p_intersected_ta, RequiredMinimumRedundancy); - if (intesection_coverage > 0 && intesection_coverage < reference_mask_coverage) { + if (intersection_coverage > 0 && intersection_coverage < reference_mask_coverage) { indices.push_back(i); } } @@ -417,45 +397,4 @@ std::vector MaskUtils::GetMasksDividingReferenceMask( KRATOS_CATCH(""); } -// template instantiations -#ifndef KRATOS_SI_APP_MASK_UTILS_INSTANTIATION -#define KRATOS_SI_APP_MASK_UTILS_INSTANTIATION(CONTAINER_TYPE) \ - template KRATOS_API(SYSTEM_IDENTIFICATION_APPLICATION) void MaskUtils::CheckCompatibility( \ - const ContainerExpression &, \ - const ContainerExpression &); \ - template KRATOS_API(SYSTEM_IDENTIFICATION_APPLICATION) std::size_t MaskUtils::GetMaskSize( \ - const ContainerExpression &, const IndexType); \ - template KRATOS_API(SYSTEM_IDENTIFICATION_APPLICATION) ContainerExpression MaskUtils::GetMask( \ - const ContainerExpression &); \ - template KRATOS_API(SYSTEM_IDENTIFICATION_APPLICATION) double MaskUtils::GetMaskThreshold( \ - const ContainerExpression &); \ - template KRATOS_API(SYSTEM_IDENTIFICATION_APPLICATION) ContainerExpression MaskUtils::GetMask( \ - const ContainerExpression &, const double); \ - template KRATOS_API(SYSTEM_IDENTIFICATION_APPLICATION) ContainerExpression MaskUtils::Union( \ - const ContainerExpression &, \ - const ContainerExpression &, const IndexType); \ - template KRATOS_API(SYSTEM_IDENTIFICATION_APPLICATION) ContainerExpression MaskUtils::Intersect( \ - const ContainerExpression &, \ - const ContainerExpression &, const IndexType); \ - template KRATOS_API(SYSTEM_IDENTIFICATION_APPLICATION) ContainerExpression MaskUtils::Subtract( \ - const ContainerExpression &, \ - const ContainerExpression &, const IndexType); \ - template KRATOS_API(SYSTEM_IDENTIFICATION_APPLICATION) ContainerExpression MaskUtils::Scale( \ - const ContainerExpression &, \ - const ContainerExpression &, const IndexType); \ - template KRATOS_API(SYSTEM_IDENTIFICATION_APPLICATION) std::vector, typename ContainerExpression::Pointer>> MaskUtils::ClusterMasks( \ - const std::vector> &, const IndexType); \ - template KRATOS_API(SYSTEM_IDENTIFICATION_APPLICATION) std::vector MaskUtils::GetMasksDividingReferenceMask( \ - const ContainerExpression &, \ - const std::vector::Pointer> &, \ - const IndexType); - -#endif - -KRATOS_SI_APP_MASK_UTILS_INSTANTIATION(ModelPart::NodesContainerType) -KRATOS_SI_APP_MASK_UTILS_INSTANTIATION(ModelPart::ConditionsContainerType) -KRATOS_SI_APP_MASK_UTILS_INSTANTIATION(ModelPart::ElementsContainerType) - -#undef KRATOS_SI_APP_MASK_UTILS_INSTANTIATION - } // namespace Kratos \ No newline at end of file diff --git a/applications/SystemIdentificationApplication/custom_utilities/mask_utils.h b/applications/SystemIdentificationApplication/custom_utilities/mask_utils.h index 5a553ae0f002..e182785b1657 100644 --- a/applications/SystemIdentificationApplication/custom_utilities/mask_utils.h +++ b/applications/SystemIdentificationApplication/custom_utilities/mask_utils.h @@ -19,7 +19,7 @@ // Project includes #include "includes/define.h" -#include "expression/container_expression.h" +#include "tensor_adaptors/tensor_adaptor.h" // Application includes @@ -45,56 +45,48 @@ class KRATOS_API(SYSTEM_IDENTIFICATION_APPLICATION) MaskUtils * This method returns number of entities of which the value is greater * than or equal to RequiredMinimumRedundancy. * - * @tparam TContainerType * @param rMask Input mask. * @param RequiredMinimumRedundancy Required minimum redundancy. * @return IndexType Number of entities above or equal to minimum redundancy. */ - template static IndexType GetMaskSize( - const ContainerExpression& rMask, + const TensorAdaptor& rMask, const IndexType RequiredMinimumRedundancy = 1); /** - * @brief Get the Mask for the given scalar expression + * @brief Get the Mask for the given scalar tensor adaptor * * The mask is computed such that the inner product between - * the mask and the scalar expression is maximized. + * the mask and the scalar tensor adaptor is maximized. * - * @tparam TContainerType Container type. - * @param rScalarExpression Input scalar expression. - * @return ContainerExpression Expression with values either 0 or 1. + * @param rScalarTensorAdaptor Input scalar tensor adaptor + * @return TensorAdaptor::Pointer TensorAdaptor with values either 0 or 1. */ - template - static ContainerExpression GetMask( - const ContainerExpression& rScalarExpression); + static TensorAdaptor::Pointer GetMask( + const TensorAdaptor& rScalarTensorAdaptor); /** * @brief Get the Mask Threshold - * @details The mask threshold is computed such that the given scalar expression + * @details The mask threshold is computed such that the given scalar tensor adaptor * is aligned to the mask with minimum cosine distance * - * @tparam TContainerType Container type. - * @param rScalarExpression Input scalar expression. - * @return double Mask threshold + * @param rScalarTensorAdaptor Input scalar tensor adaptor + * @return double Mask threshold */ - template - static double GetMaskThreshold(const ContainerExpression& rScalarExpression); + static double GetMaskThreshold(const TensorAdaptor& rScalarTensorAdaptor); /** - * @brief Get the Mask for the given scalar expression using the threshold. + * @brief Get the Mask for the given scalar tensor adaptor using the threshold. * - * The mask is computed such that all the entity values in the scalar expression + * The mask is computed such that all the entity values in the scalar tensor adaptor * which is higher than the threshold will have 1.0, others will have 0.0. * - * @tparam TContainerType Container type. - * @param rScalarExpression Input scalar expression. - * @param Threshold Threshold for mask 0 or 1 detection. - * @return ContainerExpression Expression with values either 0 or 1. + * @param rScalarTensorAdaptor Input scalar tensor adaptor + * @param Threshold Threshold for mask 0 or 1 detection. + * @return TensorAdaptor::Pointer TensorAdaptor with values either 0 or 1. */ - template - static ContainerExpression GetMask( - const ContainerExpression& rScalarExpression, + static TensorAdaptor::Pointer GetMask( + const TensorAdaptor& rScalarTensorAdaptor, const double Threshold); /** @@ -103,16 +95,14 @@ class KRATOS_API(SYSTEM_IDENTIFICATION_APPLICATION) MaskUtils * This method returns a mask with the value of RequiredMinimumRedundancy for entities * which has either in rMask1 or rMask2 a value equal or grater than RequiredMinimumRedundancy. * - * @tparam TContainerType Container type. - * @param rMask1 Mask 1 expression - * @param rMask2 Mask 2 expression + * @param rMask1 Mask 1 tensor adaptor + * @param rMask2 Mask 2 tensor adaptor * @param RequiredMinimumRedundancy Required minimum redundancy. - * @return ContainerExpression Union mask + * @return TensorAdaptor::Pointer Union mask */ - template - static ContainerExpression Union( - const ContainerExpression& rMask1, - const ContainerExpression& rMask2, + static TensorAdaptor::Pointer Union( + const TensorAdaptor& rMask1, + const TensorAdaptor& rMask2, const IndexType RequiredMinimumRedundancy = 1); /** @@ -121,51 +111,45 @@ class KRATOS_API(SYSTEM_IDENTIFICATION_APPLICATION) MaskUtils * This method returns a mask with the value of RequiredMinimumRedundancy for entities * which has equal or greater than RequiredMinimumRedundancy in both rMask1 and rMask2. * - * @tparam TContainerType Container type. - * @param rMask1 Mask 1 expression - * @param rMask2 Mask 2 expression + * @param rMask1 Mask 1 tensor adaptor + * @param rMask2 Mask 2 tensor adaptor * @param RequiredMinimumRedundancy Required minimum redundancy. - * @return ContainerExpression Intersection mask + * @return TensorAdaptor::Pointer Intersection mask */ - template - static ContainerExpression Intersect( - const ContainerExpression& rMask1, - const ContainerExpression& rMask2, + static TensorAdaptor::Pointer Intersect( + const TensorAdaptor& rMask1, + const TensorAdaptor& rMask2, const IndexType RequiredMinimumRedundancy = 1); /** * @brief Get the subtraction of two masks. * - * @tparam TContainerType Container type. - * @param rMask1 Mask 1 expression - * @param rMask2 Mask 2 expression + * @param rMask1 Mask 1 tensor adaptor + * @param rMask2 Mask 2 tensor adaptor * @param RequiredMinimumRedundancy Required minimum redundancy. - * @return ContainerExpression Subtraction mask which subtracts rMask2 from rMask1. + * @return TensorAdaptor::Pointer Subtraction mask which subtracts rMask2 from rMask1. */ - template - static ContainerExpression Subtract( - const ContainerExpression& rMask1, - const ContainerExpression& rMask2, + static TensorAdaptor::Pointer Subtract( + const TensorAdaptor& rMask1, + const TensorAdaptor& rMask2, const IndexType RequiredMinimumRedundancy = 1); /** - * @brief Scale the scalar expression with a mask. + * @brief Scale the scalar tensor adaptor with a mask. * - * This method scales the rScalarExpression with a mask of [0, 1] where mask will + * This method scales the rScalarTensorAdaptor with a mask of [0, 1] where mask will * have 1 if that corresponding entity in rMask has a value equal or greater than the * RequiredMinimumRedundancy otherwise 0. * - * @tparam TContainerType Container type. - * @param rScalarExpression Input scalar expression. + * @param rScalarTensorAdaptor Input scalar tensor adaptor * @param rMask Mask to be used. * @param RequiredMinimumRedundancy Required minimum redundancy. - * @return ContainerExpression Scaled scalar expression with the mask. + * @return TensorAdaptor::Pointer Scaled scalar tensor adaptor with the mask. */ - template - static ContainerExpression Scale( - const ContainerExpression& rScalarExpression, - const ContainerExpression& rMask, + static TensorAdaptor::Pointer Scale( + const TensorAdaptor& rScalarTensorAdaptor, + const TensorAdaptor& rMask, const IndexType RequiredMinimumRedundancy = 1); /** @@ -174,14 +158,12 @@ class KRATOS_API(SYSTEM_IDENTIFICATION_APPLICATION) MaskUtils * This method returns a list of tuples having indices list and a mask. Each indices list is a cluster * The mask for that specific cluster is stored in the 2nd element of the tuple. * - * @tparam TContainerType Container type. * @param rMasksList List of masks. * @param RequiredMinimumRedundancy Required minimum redundancy. - * @return std::vector, typename ContainerExpression::Pointer>> Tuple having list of mask indices and masks for each cluster. + * @return std::vector, TensorAdaptor::Pointer>> Tuple having list of mask indices and masks for each cluster. */ - template - static std::vector, typename ContainerExpression::Pointer>> ClusterMasks( - const std::vector>& rMasksList, + static std::vector, TensorAdaptor::Pointer>> ClusterMasks( + const std::vector::Pointer>& rMasksList, const IndexType RequiredMinimumRedundancy = 1); /** @@ -189,16 +171,14 @@ class KRATOS_API(SYSTEM_IDENTIFICATION_APPLICATION) MaskUtils * * This method returns indices of masks which can divide the given rReferenceMask. * - * @tparam TContainerType Container type. * @param rReferenceMask Reference mask. * @param rMasksList List of masks. * @param RequiredMinimumRedundancy Required minimum redundancy. * @return std::vector List of indices. */ - template static std::vector GetMasksDividingReferenceMask( - const ContainerExpression& rReferenceMask, - const std::vector::Pointer>& rMasksList, + const TensorAdaptor& rReferenceMask, + const std::vector::Pointer>& rMasksList, const IndexType RequiredMinimumRedundancy = 1); ///@} @@ -207,10 +187,9 @@ class KRATOS_API(SYSTEM_IDENTIFICATION_APPLICATION) MaskUtils ///@name Static private operations ///@{ - template static void CheckCompatibility( - const ContainerExpression& rMask1, - const ContainerExpression& rMask2); + const TensorAdaptor& rMask1, + const TensorAdaptor& rMask2); ///@} }; diff --git a/applications/SystemIdentificationApplication/tests/test_mask_utils.py b/applications/SystemIdentificationApplication/tests/test_mask_utils.py index 9de09b0479f2..96599a36ee43 100644 --- a/applications/SystemIdentificationApplication/tests/test_mask_utils.py +++ b/applications/SystemIdentificationApplication/tests/test_mask_utils.py @@ -3,7 +3,6 @@ import KratosMultiphysics as Kratos import KratosMultiphysics.KratosUnittest as UnitTest import KratosMultiphysics.SystemIdentificationApplication as KratosSI -from KratosMultiphysics.SystemIdentificationApplication.utilities.expression_utils import ExpressionUnionType class TestMaskUtils(UnitTest.TestCase): @classmethod @@ -19,14 +18,14 @@ def setUpClass(cls) -> None: node.SetValue(Kratos.HEAT_FLUX, 2 * (node.Id % 2)) def test_Union(self): - mask_1 = Kratos.Expression.NodalExpression(self.model_part) - mask_2 = Kratos.Expression.NodalExpression(self.model_part) + mask_1 = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, Kratos.PRESSURE) + mask_2 = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, Kratos.DENSITY) - Kratos.Expression.VariableExpressionIO.Read(mask_1, Kratos.PRESSURE, False) - Kratos.Expression.VariableExpressionIO.Read(mask_2, Kratos.DENSITY, False) + mask_1.CollectData() + mask_2.CollectData() - union_mask: Kratos.Expression.NodalExpression = KratosSI.MaskUtils.Union(mask_1, mask_2, 2) - Kratos.Expression.VariableExpressionIO.Write(union_mask, Kratos.TEMPERATURE, False) + union_mask = KratosSI.MaskUtils.Union(mask_1, mask_2, 2) + Kratos.TensorAdaptors.VariableTensorAdaptor(union_mask, Kratos.TEMPERATURE, copy=False).StoreData() for node in self.model_part.Nodes: if (node.Id % 3 >= 2 or node.Id % 5 >= 2): self.assertEqual(node.GetValue(Kratos.TEMPERATURE), 2) @@ -34,14 +33,14 @@ def test_Union(self): self.assertEqual(node.GetValue(Kratos.TEMPERATURE), 0) def test_Intersect(self): - mask_1 = Kratos.Expression.NodalExpression(self.model_part) - mask_2 = Kratos.Expression.NodalExpression(self.model_part) + mask_1 = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, Kratos.PRESSURE) + mask_2 = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, Kratos.DENSITY) - Kratos.Expression.VariableExpressionIO.Read(mask_1, Kratos.PRESSURE, False) - Kratos.Expression.VariableExpressionIO.Read(mask_2, Kratos.DENSITY, False) + mask_1.CollectData() + mask_2.CollectData() - union_mask: Kratos.Expression.NodalExpression = KratosSI.MaskUtils.Intersect(mask_1, mask_2, 2) - Kratos.Expression.VariableExpressionIO.Write(union_mask, Kratos.TEMPERATURE, False) + intersect_mask = KratosSI.MaskUtils.Intersect(mask_1, mask_2, 2) + Kratos.TensorAdaptors.VariableTensorAdaptor(intersect_mask, Kratos.TEMPERATURE, copy=False).StoreData() for node in self.model_part.Nodes: if (node.Id % 3 >= 2 and node.Id % 5 >= 2): self.assertEqual(node.GetValue(Kratos.TEMPERATURE), 2) @@ -49,14 +48,14 @@ def test_Intersect(self): self.assertEqual(node.GetValue(Kratos.TEMPERATURE), 0) def test_Substract(self): - mask_1 = Kratos.Expression.NodalExpression(self.model_part) - mask_2 = Kratos.Expression.NodalExpression(self.model_part) + mask_1 = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, Kratos.PRESSURE) + mask_2 = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, Kratos.DENSITY) - Kratos.Expression.VariableExpressionIO.Read(mask_1, Kratos.PRESSURE, False) - Kratos.Expression.VariableExpressionIO.Read(mask_2, Kratos.DENSITY, False) + mask_1.CollectData() + mask_2.CollectData() - union_mask: Kratos.Expression.NodalExpression = KratosSI.MaskUtils.Subtract(mask_1, mask_2, 2) - Kratos.Expression.VariableExpressionIO.Write(union_mask, Kratos.TEMPERATURE, False) + subtract_mask = KratosSI.MaskUtils.Subtract(mask_1, mask_2, 2) + Kratos.TensorAdaptors.VariableTensorAdaptor(subtract_mask, Kratos.TEMPERATURE, copy=False).StoreData() for node in self.model_part.Nodes: if (node.Id % 3 >= 2 and node.Id % 5 < 2): self.assertEqual(node.GetValue(Kratos.TEMPERATURE), 2) @@ -64,60 +63,56 @@ def test_Substract(self): self.assertEqual(node.GetValue(Kratos.TEMPERATURE), 0) def test_GetMaskSize(self): - mask = Kratos.Expression.NodalExpression(self.model_part) - Kratos.Expression.VariableExpressionIO.Read(mask, Kratos.DENSITY, False) + mask = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, Kratos.DENSITY) + mask.CollectData() self.assertEqual(KratosSI.MaskUtils.GetMaskSize(mask), self.n - self.n // 5) self.assertEqual(KratosSI.MaskUtils.GetMaskSize(mask, 2), self.n - 2 * self.n // 5) self.assertEqual(KratosSI.MaskUtils.GetMaskSize(mask, 3), self.n - 3 * self.n // 5) def test_GetMaskNoThreshold(self): - values = Kratos.Expression.NodalExpression(self.model_part) - Kratos.Expression.VariableExpressionIO.Read(values, Kratos.HEAT_FLUX, False) + values = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, Kratos.HEAT_FLUX) + values.CollectData() mask = KratosSI.MaskUtils.GetMask(values) - Kratos.Expression.VariableExpressionIO.Write(mask, Kratos.TEMPERATURE, False) + Kratos.TensorAdaptors.VariableTensorAdaptor(mask, Kratos.TEMPERATURE, copy=False).StoreData() mask_threshold = KratosSI.MaskUtils.GetMaskThreshold(values) - print(mask_threshold) mask_1 = KratosSI.MaskUtils.GetMask(values, mask_threshold) - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(mask - mask_1), 0.0) + self.assertAlmostEqual(np.linalg.norm(mask.data - mask_1.data), 0.0) for node in self.model_part.Nodes: self.assertEqual(node.GetValue(Kratos.TEMPERATURE), node.Id % 2) - def test_GetMaskWithhreshold(self): - values = Kratos.Expression.NodalExpression(self.model_part) - Kratos.Expression.VariableExpressionIO.Read(values, Kratos.HEAT_FLUX, False) + def test_GetMaskWithThreshold(self): + values = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, Kratos.HEAT_FLUX) + values.CollectData() mask = KratosSI.MaskUtils.GetMask(values, 1.0) - Kratos.Expression.VariableExpressionIO.Write(mask, Kratos.TEMPERATURE, False) + Kratos.TensorAdaptors.VariableTensorAdaptor(mask, Kratos.TEMPERATURE, copy=False).StoreData() for node in self.model_part.Nodes: self.assertEqual(node.GetValue(Kratos.TEMPERATURE), node.Id % 2) def test_Scale(self): - values = Kratos.Expression.NodalExpression(self.model_part) - Kratos.Expression.VariableExpressionIO.Read(values, Kratos.HEAT_FLUX, False) + values = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, Kratos.HEAT_FLUX) + values.CollectData() - float_exp_np = np.arange(0, self.n, dtype=np.float64) - float_exp = Kratos.Expression.NodalExpression(self.model_part) - Kratos.Expression.CArrayExpressionIO.Read(float_exp, float_exp_np) - scaled_exp_sum = np.sum(KratosSI.MaskUtils.Scale(float_exp, values).Evaluate()) + float_ta = values.Clone() + float_ta.data[:] = np.arange(0, self.n, dtype=np.float64) + scaled_exp_sum = np.sum(KratosSI.MaskUtils.Scale(float_ta, values).data) self.assertEqual(scaled_exp_sum, (self.n // 2 - 1) * (self.n // 2)) def test_ClusterMasks(self): - masks_list: 'list[Kratos.Expression.NodalExpression]' = [] + masks_list: 'list[Kratos.TensorAdaptors.DoubleTensorAdaptor]' = [] number_of_masks = 5 for i in range(number_of_masks): - mask = np.zeros((self.n), dtype=np.int32) + mask_ta = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, Kratos.PRESSURE) for j in range(self.n): - mask[j] = j % (i + 1) - mask_exp = Kratos.Expression.NodalExpression(self.model_part) - Kratos.Expression.CArrayExpressionIO.Read(mask_exp, mask) - masks_list.append(mask_exp) + mask_ta.data[j] = j % (i + 1) + masks_list.append(mask_ta) - cluster_data: 'list[tuple[list[int], ExpressionUnionType]]' = KratosSI.MaskUtils.ClusterMasks(masks_list) + cluster_data = KratosSI.MaskUtils.ClusterMasks(masks_list) reference_cluster_indices = [[], [1,2,3,4], [2,3,4], [1,3,4], [2,4], [1,2,3], [3,4]] reference_cluster_masks = np.array([ [1,0,0,0,0,0,0,0,0,0], @@ -131,24 +126,22 @@ def test_ClusterMasks(self): for i, (cluster_indices, cluster_mask) in enumerate(cluster_data): self.assertEqual(cluster_indices, reference_cluster_indices[i]) - self.assertAlmostEqual(np.linalg.norm(cluster_mask.Evaluate() - reference_cluster_masks[i, :]), 0.0, 12) + self.assertAlmostEqual(np.linalg.norm(cluster_mask.data - reference_cluster_masks[i, :]), 0.0, 12) def test_GetMasksDividingReferenceMask(self): - masks_list: 'list[Kratos.Expression.NodalExpression]' = [] + masks_list: 'list[Kratos.TensorAdaptors.DoubleTensorAdaptor]' = [] number_of_masks = 5 for i in range(number_of_masks): - mask = np.zeros((self.n), dtype=np.int32) + mask_ta = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, Kratos.PRESSURE) for j in range(self.n): - mask[j] = j % (i + 1) - mask_exp = Kratos.Expression.NodalExpression(self.model_part) - Kratos.Expression.CArrayExpressionIO.Read(mask_exp, mask) - masks_list.append(mask_exp) + mask_ta.data[j] = j % (i + 1) + masks_list.append(mask_ta) ref_mask = np.zeros((self.n), dtype=np.int32) ref_mask[3:5] = 1 - ref_mask_exp = Kratos.Expression.NodalExpression(self.model_part) - Kratos.Expression.CArrayExpressionIO.Read(ref_mask_exp, ref_mask) - indices = KratosSI.MaskUtils.GetMasksDividingReferenceMask(ref_mask_exp, masks_list) + ref_mask_ta = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Nodes, Kratos.PRESSURE) + ref_mask_ta.data[:] = ref_mask + indices = KratosSI.MaskUtils.GetMasksDividingReferenceMask(ref_mask_ta, masks_list) self.assertEqual(indices, [1,2,3]) From 3ef65fda6b24c90b86a0408b8a04745b9e6b3e9d Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Tue, 17 Feb 2026 11:54:25 +0100 Subject: [PATCH 093/116] update distancematrix to ta --- .../add_custom_utilities_to_python.cpp | 2 +- .../custom_utilities/distance_matrix.cpp | 46 +++++++++---------- .../custom_utilities/distance_matrix.h | 8 +--- .../tests/test_distance_matrix.py | 6 +-- 4 files changed, 27 insertions(+), 35 deletions(-) diff --git a/applications/SystemIdentificationApplication/custom_python/add_custom_utilities_to_python.cpp b/applications/SystemIdentificationApplication/custom_python/add_custom_utilities_to_python.cpp index 506cbaf0fd88..e3f28d207e49 100644 --- a/applications/SystemIdentificationApplication/custom_python/add_custom_utilities_to_python.cpp +++ b/applications/SystemIdentificationApplication/custom_python/add_custom_utilities_to_python.cpp @@ -63,7 +63,7 @@ void AddCustomUtilitiesToPython(pybind11::module& m) py::class_(m, "DistanceMatrix") .def(py::init<>()) - .def("Update", &DistanceMatrix::Update, py::arg("values_container_expression")) + .def("Update", &DistanceMatrix::Update, py::arg("values_container_tensor_adaptor")) .def("GetDistance", py::overload_cast(&DistanceMatrix::GetDistance, py::const_), py::arg("index_i"), py::arg("index_j")) .def("GetEntriesSize", &DistanceMatrix::GetEntriesSize) .def("GetNumberOfItems", &DistanceMatrix::GetNumberOfItems) diff --git a/applications/SystemIdentificationApplication/custom_utilities/distance_matrix.cpp b/applications/SystemIdentificationApplication/custom_utilities/distance_matrix.cpp index 8cc1b9b5f854..e3c8f370b3cd 100644 --- a/applications/SystemIdentificationApplication/custom_utilities/distance_matrix.cpp +++ b/applications/SystemIdentificationApplication/custom_utilities/distance_matrix.cpp @@ -31,40 +31,36 @@ DistanceMatrix::DistanceMatrix() { } -void DistanceMatrix::Update( - std::variant< - ContainerExpression::Pointer, - ContainerExpression::Pointer, - ContainerExpression::Pointer> pDistancesExpression) +void DistanceMatrix::Update(const TensorAdaptor& rDistancesTensorAdaptor) { KRATOS_TRY - std::visit([&](const auto& pExp) { - this->mN = pExp->GetContainer().size(); - this->mDistances.resize(this->GetEntriesSize()); + auto shape = rDistancesTensorAdaptor.Shape(); - const auto& r_expression = pExp->GetExpression(); - const auto dimensionality = r_expression.GetItemComponentCount(); + this->mN = shape[0]; + this->mDistances.resize(this->GetEntriesSize()); - IndexPartition(this->mDistances.size()).for_each([&](const auto Index) { - const auto& index_pair = GetIndexPair(Index); + const auto data_view = rDistancesTensorAdaptor.ViewData(); + const auto dimensionality = data_view.size() / shape[0]; - const auto i_index = std::get<0>(index_pair); - const auto i_data_begin = i_index * dimensionality; - const auto j_index = std::get<1>(index_pair); - const auto j_data_begin = j_index * dimensionality; + IndexPartition(this->mDistances.size()).for_each([&](const auto Index) { + const auto& index_pair = GetIndexPair(Index); - double distance = 0.0; + const auto i_index = std::get<0>(index_pair); + const auto i_data_begin = i_index * dimensionality; + const auto j_index = std::get<1>(index_pair); + const auto j_data_begin = j_index * dimensionality; - for (IndexType i_comp = 0; i_comp < dimensionality; ++i_comp) { - const double i_value = r_expression.Evaluate(i_index, i_data_begin, i_comp); - const double j_value = r_expression.Evaluate(j_index, j_data_begin, i_comp); - distance += std::pow(i_value - j_value, 2.0); - } + double distance = 0.0; - mDistances[Index] = std::sqrt(distance); - }); - }, pDistancesExpression); + for (IndexType i_comp = 0; i_comp < dimensionality; ++i_comp) { + const double i_value = data_view[i_data_begin + i_comp]; + const double j_value = data_view[j_data_begin + i_comp]; + distance += std::pow(i_value - j_value, 2.0); + } + + mDistances[Index] = std::sqrt(distance); + }); KRATOS_CATCH(""); } diff --git a/applications/SystemIdentificationApplication/custom_utilities/distance_matrix.h b/applications/SystemIdentificationApplication/custom_utilities/distance_matrix.h index ccb1f201fc61..1b808e5e2df5 100644 --- a/applications/SystemIdentificationApplication/custom_utilities/distance_matrix.h +++ b/applications/SystemIdentificationApplication/custom_utilities/distance_matrix.h @@ -20,7 +20,7 @@ // Project includes #include "includes/define.h" #include "includes/model_part.h" -#include "expression/container_expression.h" +#include "tensor_adaptors/tensor_adaptor.h" // Application includes @@ -64,11 +64,7 @@ class KRATOS_API(SYSTEM_IDENTIFICATION_APPLICATION) DistanceMatrix IndexType GetNumberOfItems() const; - void Update( - std::variant< - ContainerExpression::Pointer, - ContainerExpression::Pointer, - ContainerExpression::Pointer> pDistancesExpression); + void Update(const TensorAdaptor& rDistancesTensorAdaptor); ///@} diff --git a/applications/SystemIdentificationApplication/tests/test_distance_matrix.py b/applications/SystemIdentificationApplication/tests/test_distance_matrix.py index a9522e87cd70..d80c85e53107 100644 --- a/applications/SystemIdentificationApplication/tests/test_distance_matrix.py +++ b/applications/SystemIdentificationApplication/tests/test_distance_matrix.py @@ -13,9 +13,9 @@ def setUpClass(cls) -> None: cls.distance_matrix = KratosSI.DistanceMatrix() - exp = Kratos.Expression.NodalExpression(cls.model_part) - Kratos.Expression.NodalPositionExpressionIO.Read(exp, Kratos.Configuration.Initial) - cls.distance_matrix.Update(exp) + ta = Kratos.TensorAdaptors.NodePositionTensorAdaptor(cls.model_part.Nodes, Kratos.Configuration.Initial) + ta.CollectData() + cls.distance_matrix.Update(ta) def test_GetDistance1(self) -> None: for i, node_i in enumerate(self.model_part.Nodes): From 637d4b2ca677962037cdc8a90be4b5d6ee9fdbca Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Tue, 17 Feb 2026 12:21:04 +0100 Subject: [PATCH 094/116] update exp utils to ta utils --- .../python_scripts/utilities/data_utils.py | 6 -- .../utilities/expression_utils.py | 72 ------------------- .../python_scripts/utilities/sensor_utils.py | 1 - .../utilities/tensor_adaptor_utils.py | 63 ++++++++++++++++ .../tests/test_sensor_utils.py | 43 ++++++----- 5 files changed, 90 insertions(+), 95 deletions(-) delete mode 100644 applications/SystemIdentificationApplication/python_scripts/utilities/expression_utils.py create mode 100644 applications/SystemIdentificationApplication/python_scripts/utilities/tensor_adaptor_utils.py diff --git a/applications/SystemIdentificationApplication/python_scripts/utilities/data_utils.py b/applications/SystemIdentificationApplication/python_scripts/utilities/data_utils.py index 62f126ba372d..817956e885c4 100644 --- a/applications/SystemIdentificationApplication/python_scripts/utilities/data_utils.py +++ b/applications/SystemIdentificationApplication/python_scripts/utilities/data_utils.py @@ -3,12 +3,6 @@ import KratosMultiphysics as Kratos import KratosMultiphysics.SystemIdentificationApplication as KratosSI -SensorViewUnionType = typing.Union[ - KratosSI.Sensors.NodalSensorView, - KratosSI.Sensors.ConditionSensorView, - KratosSI.Sensors.ElementSensorView - ] - SupportedVariableUnionType = typing.Union[ Kratos.BoolVariable, Kratos.IntegerVariable, diff --git a/applications/SystemIdentificationApplication/python_scripts/utilities/expression_utils.py b/applications/SystemIdentificationApplication/python_scripts/utilities/expression_utils.py deleted file mode 100644 index 0f35e8249c8a..000000000000 --- a/applications/SystemIdentificationApplication/python_scripts/utilities/expression_utils.py +++ /dev/null @@ -1,72 +0,0 @@ -import typing -from enum import Enum -import KratosMultiphysics as Kratos -import KratosMultiphysics.OptimizationApplication as KratosOA - -class PropertiesDataLocation(Enum): - ElementProperties = 100 - ConditionProperties = 200 - -class ExpressionDataLocation(Kratos.Globals.DataLocation): - ElementProperties = PropertiesDataLocation.ElementProperties, - ConditionProperties = PropertiesDataLocation.ConditionProperties - -ExpressionUnionType = typing.Union[ - Kratos.Expression.NodalExpression, - Kratos.Expression.ConditionExpression, - Kratos.Expression.ElementExpression] - -def GetContainerExpressionType(data_location: ExpressionDataLocation) -> 'typing.Union[typing.Type[Kratos.Expression.NodalExpression], typing.Type[Kratos.Expression.ConditionExpression], typing.Type[Kratos.Expression.ElementExpression]]': - if data_location in [ExpressionDataLocation.NodeHistorical, ExpressionDataLocation.NodeNonHistorical]: - return Kratos.Expression.NodalExpression - elif data_location == ExpressionDataLocation.Condition or data_location == ExpressionDataLocation.ConditionProperties: - return Kratos.Expression.ConditionExpression - elif data_location == ExpressionDataLocation.Element or data_location == ExpressionDataLocation.ElementProperties: - return Kratos.Expression.ElementExpression - else: - raise RuntimeError(f"Unsupported {data_location}.") - -def GetContainerExpression(model_part: Kratos.ModelPart, data_location: ExpressionDataLocation, variable: typing.Any) -> ExpressionUnionType: - cexp_type = GetContainerExpressionType(data_location) - expression = cexp_type(model_part) - if data_location == ExpressionDataLocation.NodeHistorical: - Kratos.Expression.VariableExpressionIO.Read(expression, variable, True) - elif data_location == ExpressionDataLocation.NodeNonHistorical: - Kratos.Expression.VariableExpressionIO.Read(expression, variable, False) - elif data_location == ExpressionDataLocation.Condition: - Kratos.Expression.VariableExpressionIO.Read(expression, variable) - elif data_location == ExpressionDataLocation.Element: - Kratos.Expression.VariableExpressionIO.Read(expression, variable) - elif data_location == ExpressionDataLocation.ConditionProperties or data_location == ExpressionDataLocation.ElementProperties: - KratosOA.PropertiesVariableExpressionIO.Read(expression, variable) - else: - raise RuntimeError(f"Unsupported {data_location}.") - return expression - -class ExpressionBoundingManager: - def __init__(self, bounds: 'list[float]') -> None: - """ - This class is used to bound values of an expression to specified interval. - If a value in an expression is above the max value of bounds, then it will have a value larger than 1.0 - if a value in an expression is below the min value of bounds, then it will have a value smaller than 0.0 - Values in an expression will be linearly interpolated and mapped from interval [min(bounds), max(bounds)] - to [0, 1]. - - Args: - bounds (list[float]): Bounds of the given expression values. - - Raises: - RuntimeError: If bounds does not contain two values. - """ - if len(bounds) != 2: - raise RuntimeError(f"The bounds should be of size 2. [bounds = {bounds}]") - self.bounds = sorted(bounds) - - def GetBoundGap(self) -> float: - return self.bounds[1] - self.bounds[0] - - def GetBoundedExpression(self, unbounded_expression: ExpressionUnionType) -> ExpressionUnionType: - return (unbounded_expression - self.bounds[0]) / self.GetBoundGap() - - def GetUnboundedExpression(self, bounded_expression: ExpressionUnionType) -> ExpressionUnionType: - return bounded_expression * self.GetBoundGap() + self.bounds[0] diff --git a/applications/SystemIdentificationApplication/python_scripts/utilities/sensor_utils.py b/applications/SystemIdentificationApplication/python_scripts/utilities/sensor_utils.py index 6d0a99a61520..592b79f2ea79 100644 --- a/applications/SystemIdentificationApplication/python_scripts/utilities/sensor_utils.py +++ b/applications/SystemIdentificationApplication/python_scripts/utilities/sensor_utils.py @@ -9,7 +9,6 @@ from KratosMultiphysics.SystemIdentificationApplication.utilities.data_utils import GetParameterToKratosValuesConverter from KratosMultiphysics.SystemIdentificationApplication.utilities.data_utils import GetKratosValueToCSVStringConverter from KratosMultiphysics.SystemIdentificationApplication.utilities.data_utils import GetNameToCSVString -from KratosMultiphysics.SystemIdentificationApplication.utilities.expression_utils import GetContainerExpressionType from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView def CreateSensors(sensor_model_part: Kratos.ModelPart, domain_model_part: Kratos.ModelPart, list_of_parameters: 'list[Kratos.Parameters]') -> 'list[KratosSI.Sensors.Sensor]': diff --git a/applications/SystemIdentificationApplication/python_scripts/utilities/tensor_adaptor_utils.py b/applications/SystemIdentificationApplication/python_scripts/utilities/tensor_adaptor_utils.py new file mode 100644 index 000000000000..23bad7a91ad9 --- /dev/null +++ b/applications/SystemIdentificationApplication/python_scripts/utilities/tensor_adaptor_utils.py @@ -0,0 +1,63 @@ +import typing +from enum import Enum +import KratosMultiphysics as Kratos +import KratosMultiphysics.OptimizationApplication as KratosOA + +class PropertiesDataLocation(Enum): + ElementProperties = 100 + ConditionProperties = 200 + +class TensorAdaptorDataLocation(Kratos.Globals.DataLocation): + ElementProperties = PropertiesDataLocation.ElementProperties, + ConditionProperties = PropertiesDataLocation.ConditionProperties + +def GetTensorAdaptor(model_part: Kratos.ModelPart, data_location: TensorAdaptorDataLocation, variable: typing.Any) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + if data_location == TensorAdaptorDataLocation.NodeHistorical: + ta = Kratos.TensorAdaptors.HistoricalVariableTensorAdaptor(model_part.Nodes, variable) + elif data_location == TensorAdaptorDataLocation.NodeNonHistorical: + ta = Kratos.TensorAdaptors.VariableTensorAdaptor(model_part.Nodes, variable) + elif data_location == TensorAdaptorDataLocation.Condition: + ta = Kratos.TensorAdaptors.VariableTensorAdaptor(model_part.Conditions, variable) + elif data_location == TensorAdaptorDataLocation.Element: + ta = Kratos.TensorAdaptors.VariableTensorAdaptor(model_part.Elements, variable) + elif data_location == TensorAdaptorDataLocation.ConditionProperties: + ta = KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(model_part.Conditions, variable) + elif data_location == TensorAdaptorDataLocation.ElementProperties: + ta = KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(model_part.Elements, variable) + else: + raise RuntimeError(f"Unsupported {data_location}.") + + ta.CollectData() + return ta + +class TensorAdaptorBoundingManager: + def __init__(self, bounds: 'list[float]') -> None: + """ + This class is used to bound values of an tensor adaptor to specified interval. + If a value in an tensor adaptor is above the max value of bounds, then it will have a value larger than 1.0 + if a value in an tensor adaptor is below the min value of bounds, then it will have a value smaller than 0.0 + Values in an tensor adaptor will be linearly interpolated and mapped from interval [min(bounds), max(bounds)] + to [0, 1]. + + Args: + bounds (list[float]): Bounds of the given tensor adaptor values. + + Raises: + RuntimeError: If bounds does not contain two values. + """ + if len(bounds) != 2: + raise RuntimeError(f"The bounds should be of size 2. [bounds = {bounds}]") + self.bounds = sorted(bounds) + + def GetBoundGap(self) -> float: + return self.bounds[1] - self.bounds[0] + + def GetBoundedTensorAdaptor(self, unbounded_tensor_adaptor: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + result = unbounded_tensor_adaptor.Clone() + result.data[:] = (result.data[:] - self.bounds[0]) / self.GetBoundGap() + return result + + def GetUnboundedTensorAdaptor(self, bounded_tensor_adaptor: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + result = bounded_tensor_adaptor.Clone() + result.data[:] = (result.data[:] * self.GetBoundGap() + self.bounds[0]) + return result diff --git a/applications/SystemIdentificationApplication/tests/test_sensor_utils.py b/applications/SystemIdentificationApplication/tests/test_sensor_utils.py index 6bd9c381e09e..294704942b04 100644 --- a/applications/SystemIdentificationApplication/tests/test_sensor_utils.py +++ b/applications/SystemIdentificationApplication/tests/test_sensor_utils.py @@ -1,3 +1,4 @@ +import numpy as np import KratosMultiphysics as Kratos import KratosMultiphysics.SystemIdentificationApplication as KratosSI import KratosMultiphysics.KratosUnittest as UnitTest @@ -73,35 +74,45 @@ def setUpClass(cls) -> None: cls.sensors = CreateSensors(cls.sensor_model_part, cls.model_part, parameters) - nodal_exp = Kratos.Expression.NodalExpression(cls.model_part) - Kratos.Expression.VariableExpressionIO.Read(nodal_exp, Kratos.DISPLACEMENT, True) + nodal_ta = Kratos.TensorAdaptors.HistoricalVariableTensorAdaptor(cls.model_part.Nodes, Kratos.DISPLACEMENT) + nodal_ta.CollectData() - elemental_exp = Kratos.Expression.ElementExpression(cls.model_part) - Kratos.Expression.VariableExpressionIO.Read(elemental_exp, Kratos.PRESSURE) + elemental_ta = Kratos.TensorAdaptors.VariableTensorAdaptor(cls.model_part.Elements, Kratos.PRESSURE) + elemental_ta.CollectData() for sensor in cls.sensors: - sensor.AddContainerExpression("nodal_exp", nodal_exp * (sensor.GetNode().Id)) - sensor.AddContainerExpression("element_exp", elemental_exp * (sensor.GetNode(). Id ** 2)) + ta = nodal_ta.Clone() + ta.data[:] *= sensor.GetNode().Id + sensor.AddTensorAdaptor("nodal_ta", ta) + + ta = elemental_ta.Clone() + ta.data[:] *= sensor.GetNode(). Id ** 2 + sensor.AddTensorAdaptor("element_ta", ta) def test_CreateSensorView(self): n_nodes = self.model_part.NumberOfNodes() for sensor in self.sensors: - nodal_sensor_view: KratosSI.Sensors.NodalSensorView = KratosSI.SensorUtils.CreateSensorView(sensor, "nodal_exp") - self.assertAlmostEqual((3 * n_nodes * (n_nodes + 1) / 2 + 3 * n_nodes) * sensor.GetNode().Id, Kratos.Expression.Utils.Sum(nodal_sensor_view.GetContainerExpression())) + nodal_sensor_view = KratosSI.Sensors.SensorView(sensor, "nodal_ta") + self.assertAlmostEqual((3 * n_nodes * (n_nodes + 1) / 2 + 3 * n_nodes) * sensor.GetNode().Id, np.sum(nodal_sensor_view.GetTensorAdaptor().data)) - element_sensor_view: KratosSI.Sensors.ElementSensorView = KratosSI.SensorUtils.CreateSensorView(sensor, "element_exp") - self.assertAlmostEqual(110 * sensor.GetNode().Id ** 2, Kratos.Expression.Utils.Sum(element_sensor_view.GetContainerExpression())) + element_sensor_view = KratosSI.Sensors.SensorView(sensor, "element_ta") + self.assertAlmostEqual(110 * sensor.GetNode().Id ** 2, np.sum(element_sensor_view.GetTensorAdaptor().data)) - def test_SensorViewAuxiliaryExps(self): + def test_SensorViewAuxiliaryTensorAdaptors(self): for sensor in self.sensors: - nodal_sensor_view: KratosSI.Sensors.NodalSensorView = KratosSI.SensorUtils.CreateSensorView(sensor, "nodal_exp") - nodal_sensor_view.AddAuxiliaryExpression("mapped_id", nodal_sensor_view.GetContainerExpression() * sensor.GetNode().Id) - nodal_sensor_view.AddAuxiliaryExpression("mapped_id_square", nodal_sensor_view.GetContainerExpression() * sensor.GetNode().Id ** 2) + nodal_sensor_view = KratosSI.Sensors.SensorView(sensor, "nodal_ta") + ta = nodal_sensor_view.GetTensorAdaptor().Clone() + ta.data[:] *= sensor.GetNode().Id + nodal_sensor_view.AddAuxiliaryTensorAdaptor("mapped_id", ta) + + ta = nodal_sensor_view.GetTensorAdaptor().Clone() + ta.data[:] *= sensor.GetNode().Id ** 2 + nodal_sensor_view.AddAuxiliaryTensorAdaptor("mapped_id_square", ta) self.assertIn("mapped_id", nodal_sensor_view.GetAuxiliarySuffixes()) self.assertIn("mapped_id_square", nodal_sensor_view.GetAuxiliarySuffixes()) - self.assertEqual(Kratos.Expression.Utils.NormInf(nodal_sensor_view.GetAuxiliaryExpression("mapped_id") - nodal_sensor_view.GetContainerExpression() * sensor.GetNode().Id), 0.0) - self.assertEqual(Kratos.Expression.Utils.NormInf(nodal_sensor_view.GetAuxiliaryExpression("mapped_id_square") - nodal_sensor_view.GetContainerExpression() * sensor.GetNode().Id ** 2), 0.0) + self.assertEqual(np.linalg.norm(nodal_sensor_view.GetAuxiliaryTensorAdaptor("mapped_id").data - nodal_sensor_view.GetTensorAdaptor().data[:] * sensor.GetNode().Id), 0.0) + self.assertEqual(np.linalg.norm(nodal_sensor_view.GetAuxiliaryTensorAdaptor("mapped_id_square").data - nodal_sensor_view.GetTensorAdaptor().data[:] * sensor.GetNode().Id ** 2), 0.0) def test_SetGetSensors(self): opt_prob = OptimizationProblem() From 834a0a56ff68c34f61f9a4c72926f9e58e4f4724 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Tue, 17 Feb 2026 13:44:30 +0100 Subject: [PATCH 095/116] update data_values_control to TA --- .../controls/data_values_control.py | 124 ++++++------------ .../controls/test_data_values_control.py | 42 +++--- 2 files changed, 64 insertions(+), 102 deletions(-) diff --git a/applications/SystemIdentificationApplication/python_scripts/controls/data_values_control.py b/applications/SystemIdentificationApplication/python_scripts/controls/data_values_control.py index aaa96dfde02b..4b4a9ffa9da5 100644 --- a/applications/SystemIdentificationApplication/python_scripts/controls/data_values_control.py +++ b/applications/SystemIdentificationApplication/python_scripts/controls/data_values_control.py @@ -1,17 +1,15 @@ -import math +import math, numpy from typing import Optional import KratosMultiphysics as Kratos import KratosMultiphysics.SystemIdentificationApplication as KratosSI from KratosMultiphysics.OptimizationApplication.controls.control import Control -from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import ContainerExpressionTypes from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes -from KratosMultiphysics.OptimizationApplication.utilities.helper_utilities import IsSameContainerExpression from KratosMultiphysics.OptimizationApplication.utilities.model_part_utilities import ModelPartOperation from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import TimeLogger from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem -from KratosMultiphysics.SystemIdentificationApplication.utilities.expression_utils import ExpressionBoundingManager +from KratosMultiphysics.SystemIdentificationApplication.utilities.tensor_adaptor_utils import TensorAdaptorBoundingManager, GetTensorAdaptor from KratosMultiphysics.OptimizationApplication.filtering.filter import Factory as FilterFactory def Factory(model: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem) -> Control: @@ -30,50 +28,6 @@ class DataValuesControl(Control): for the specified control variable. This does not do any filtering. """ - class __ElementValueControlHelper: - clamper_type = KratosSI.ElementSmoothClamper - data_location = Kratos.Globals.DataLocation.Element - expression_type = Kratos.Expression.ElementExpression - - def ReadExpression(self, exp, var): - Kratos.Expression.VariableExpressionIO.Read(exp, var) - - def WriteExpression(self, exp, var): - Kratos.Expression.VariableExpressionIO.Write(exp, var) - - class __ConditionValueControlHelper: - clamper_type = KratosSI.ConditionSmoothClamper - data_location = Kratos.Globals.DataLocation.Condition - expression_type = Kratos.Expression.ConditionExpression - - def ReadExpression(self, exp, var): - Kratos.Expression.VariableExpressionIO.Read(exp, var) - - def WriteExpression(self, exp, var): - Kratos.Expression.VariableExpressionIO.Write(exp, var) - - class __NodalValueControlHelper: - clamper_type = KratosSI.NodeSmoothClamper - data_location = Kratos.Globals.DataLocation.NodeNonHistorical - expression_type = Kratos.Expression.NodalExpression - - def ReadExpression(self, exp, var): - Kratos.Expression.VariableExpressionIO.Read(exp, var, False) - - def WriteExpression(self, exp, var): - Kratos.Expression.VariableExpressionIO.Write(exp, var, False) - - class __NodalHistoricalValueControlHelper: - clamper_type = KratosSI.NodeSmoothClamper - data_location = Kratos.Globals.DataLocation.NodeHistorical - expression_type = Kratos.Expression.NodalExpression - - def ReadExpression(self, exp, var): - Kratos.Expression.VariableExpressionIO.Read(exp, var, True) - - def WriteExpression(self, exp, var): - Kratos.Expression.VariableExpressionIO.Write(exp, var, True) - def __init__(self, name: str, model: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem): super().__init__(name) @@ -94,17 +48,16 @@ def __init__(self, name: str, model: Kratos.Model, parameters: Kratos.Parameters parameters.ValidateAndAssignDefaults(default_settings) allowed_container_types = { - "nodal_historical": self.__NodalHistoricalValueControlHelper, - "nodal_nonhistorical": self.__NodalValueControlHelper, - "condition": self.__ConditionValueControlHelper, - "element": self.__ElementValueControlHelper + "nodal_historical": Kratos.Globals.DataLocation.NodeHistorical, + "nodal_nonhistorical": Kratos.Globals.DataLocation.NodeNonHistorical, + "condition": Kratos.Globals.DataLocation.Condition, + "element": Kratos.Globals.DataLocation.Element } container_type = parameters["container_type"].GetString() if container_type not in allowed_container_types.keys(): raise RuntimeError(f"Unsupported container type = \"{container_type}\". Allowed container types are:\n\t" + "\n\t".join(list(allowed_container_types.keys()))) else: - self.helper = allowed_container_types[container_type] - self.container_type_helper = self.helper() + self.container_type = allowed_container_types[container_type] self.model : Kratos.Model = model self.parameters = parameters @@ -139,7 +92,7 @@ def __init__(self, name: str, model: Kratos.Model, parameters: Kratos.Parameters # for filtering. The adjoint model part may re-assign adjoint elements based on # the primal model part rendering the filter element pointers useless and to segfault. # hence filter is using the primal model part to get the locations. - self.filter = FilterFactory(self.model, self.primal_model_part_operation.GetModelPartFullName(), self.controlled_physical_variable, self.container_type_helper.data_location, self.parameters["filter_settings"]) + self.filter = FilterFactory(self.model, self.primal_model_part_operation.GetModelPartFullName(), self.controlled_physical_variable, self.container_type, self.parameters["filter_settings"]) self.primal_model_part: Optional[Kratos.ModelPart] = None self.adjoint_model_part: Optional[Kratos.ModelPart] = None @@ -147,8 +100,8 @@ def __init__(self, name: str, model: Kratos.Model, parameters: Kratos.Parameters control_variable_bounds = parameters["control_variable_bounds"].GetVector() # use the clamper in the unit interval - self.interval_bounder = ExpressionBoundingManager(control_variable_bounds) - self.clamper = self.container_type_helper.clamper_type(0, 1) + self.interval_bounder = TensorAdaptorBoundingManager(control_variable_bounds) + self.clamper = KratosSI.SmoothClamper(0, 1) def Initialize(self) -> None: self.primal_model_part = self.primal_model_part_operation.GetModelPart() @@ -161,12 +114,13 @@ def Initialize(self) -> None: physical_field = self.GetPhysicalField() # get the phi field which is in [0, 1] range - self.physical_phi_field = self.clamper.ProjectBackward(self.interval_bounder.GetBoundedExpression(physical_field)) + self.physical_phi_field = self.clamper.ProjectBackward(self.interval_bounder.GetBoundedTensorAdaptor(physical_field)) # compute the control phi field self.control_phi_field = self.filter.UnfilterField(self.physical_phi_field) - self.physical_phi_derivative_field = self.clamper.CalculateForwardProjectionGradient(self.physical_phi_field) * self.interval_bounder.GetBoundGap() + self.physical_phi_derivative_field = self.clamper.CalculateForwardProjectionGradient(self.physical_phi_field) + self.physical_phi_derivative_field.data[:] *= self.interval_bounder.GetBoundGap() self._UpdateAndOutputFields(self.GetEmptyField()) @@ -179,44 +133,47 @@ def Finalize(self) -> None: def GetPhysicalKratosVariables(self) -> 'list[SupportedSensitivityFieldVariableTypes]': return [self.controlled_physical_variable] - def GetEmptyField(self) -> ContainerExpressionTypes: - field = self.container_type_helper.expression_type(self.primal_model_part) - Kratos.Expression.LiteralExpressionIO.SetData(field, 0.0) + def GetEmptyField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + field = GetTensorAdaptor(self.primal_model_part, self.container_type, self.controlled_physical_variable) + field.data[:] = 0.0 return field - def GetControlField(self) -> ContainerExpressionTypes: - return self.control_phi_field + def GetControlField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + return self.control_phi_field.Clone() - def GetPhysicalField(self) -> ContainerExpressionTypes: - physical_thickness_field = self.container_type_helper.expression_type(self.primal_model_part) - self.container_type_helper.ReadExpression(physical_thickness_field, self.controlled_physical_variable) + def GetPhysicalField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + physical_thickness_field = GetTensorAdaptor(self.primal_model_part, self.container_type, self.controlled_physical_variable) + physical_thickness_field.CollectData() return physical_thickness_field - def MapGradient(self, physical_gradient_variable_container_expression_map: 'dict[SupportedSensitivityFieldVariableTypes, ContainerExpressionTypes]') -> ContainerExpressionTypes: + def MapGradient(self, physical_gradient_variable_tensor_adaptor_map: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleTensorAdaptor]') -> Kratos.TensorAdaptors.DoubleTensorAdaptor: with TimeLogger("DataValuesControl::MapGradient", None, "Finished",False): - keys = physical_gradient_variable_container_expression_map.keys() + keys = physical_gradient_variable_tensor_adaptor_map.keys() if len(keys) != 1: raise RuntimeError(f"Provided more than required gradient fields for control \"{self.GetName()}\". Following are the variables:\n\t" + "\n\t".join([k.Name() for k in keys])) if self.controlled_physical_variable not in keys: raise RuntimeError(f"The required gradient for control \"{self.GetName()}\" w.r.t. {self.controlled_physical_variable.Name()} not found. Followings are the variables:\n\t" + "\n\t".join([k.Name() for k in keys])) - physical_gradient = physical_gradient_variable_container_expression_map[self.controlled_physical_variable] - if not IsSameContainerExpression(physical_gradient, self.GetEmptyField()): + physical_gradient = physical_gradient_variable_tensor_adaptor_map[self.controlled_physical_variable] + if physical_gradient.GetContainer() != self.GetEmptyField().GetContainer(): raise RuntimeError(f"Gradients for the required element container not found for control \"{self.GetName()}\". [ required model part name: {self.primal_model_part.FullName()}, given model part name: {physical_gradient.GetModelPart().FullName()} ]") # dj/dE -> physical_gradient # dj/dphi = dj/dphysical * dphysical/dphi - return self.filter.BackwardFilterIntegratedField(physical_gradient * self.physical_phi_derivative_field) + dj_dphi = physical_gradient.Clone() + dj_dphi.data[:] *= self.physical_phi_derivative_field.data + return self.filter.BackwardFilterIntegratedField(dj_dphi) - def Update(self, new_control_field: ContainerExpressionTypes) -> bool: - if not IsSameContainerExpression(new_control_field, self.GetEmptyField()): + def Update(self, new_control_field: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> bool: + if new_control_field.GetContainer() != self.GetEmptyField().GetContainer(): raise RuntimeError(f"Updates for the required element container not found for control \"{self.GetName()}\". [ required model part name: {self.primal_model_part.FullName()}, given model part name: {control_field.GetModelPart().FullName()} ]") - update = new_control_field - self.control_phi_field - if not math.isclose(Kratos.Expression.Utils.NormL2(update), 0.0, abs_tol=1e-16): + update = new_control_field.Clone() + update.data[:] -= self.control_phi_field.data + if not math.isclose(numpy.linalg.norm(update.data), 0.0, abs_tol=1e-16): with TimeLogger(self.__class__.__name__, f"Updating {self.GetName()}...", f"Finished updating of {self.GetName()}.",False): # update the control thickness field - self.control_phi_field = new_control_field + self.control_phi_field.data[:] = new_control_field.data # now update the physical field self._UpdateAndOutputFields(update) @@ -225,20 +182,23 @@ def Update(self, new_control_field: ContainerExpressionTypes) -> bool: return True return False - def _UpdateAndOutputFields(self, update: ContainerExpressionTypes) -> None: + def _UpdateAndOutputFields(self, update: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> None: # filter the control field filtered_phi_field_update = self.filter.ForwardFilterField(update) - self.physical_phi_field = Kratos.Expression.Utils.Collapse(self.physical_phi_field + filtered_phi_field_update) + self.physical_phi_field.data[:] += filtered_phi_field_update.data # project forward the filtered thickness field to get clamped physical field - physical_field = self.interval_bounder.GetUnboundedExpression(self.clamper.ProjectForward(self.physical_phi_field)) + physical_field = self.interval_bounder.GetUnboundedTensorAdaptor(self.clamper.ProjectForward(self.physical_phi_field)) # now update physical field - self.container_type_helper.WriteExpression(physical_field, self.controlled_physical_variable) + ta = GetTensorAdaptor(self.primal_model_part, self.container_type, self.controlled_physical_variable) + ta.data[:] = physical_field.data + ta.StoreData() # compute and store projection derivatives for consistent filtering of the sensitivities # this is dphi/dphysical -> physical_phi_derivative_field - self.physical_phi_derivative_field = self.clamper.CalculateForwardProjectionGradient(self.physical_phi_field) * self.interval_bounder.GetBoundGap() + self.physical_phi_derivative_field = self.clamper.CalculateForwardProjectionGradient(self.physical_phi_field) + self.physical_phi_derivative_field.data[:] *= self.interval_bounder.GetBoundGap() # now output the fields un_buffered_data = ComponentDataView(self, self.optimization_problem).GetUnBufferedData() diff --git a/applications/SystemIdentificationApplication/tests/controls/test_data_values_control.py b/applications/SystemIdentificationApplication/tests/controls/test_data_values_control.py index b9f493160f68..526705433058 100644 --- a/applications/SystemIdentificationApplication/tests/controls/test_data_values_control.py +++ b/applications/SystemIdentificationApplication/tests/controls/test_data_values_control.py @@ -1,3 +1,4 @@ +import numpy as np import KratosMultiphysics as Kratos import KratosMultiphysics.StructuralMechanicsApplication as KratosSM import KratosMultiphysics.KratosUnittest as kratos_unittest @@ -71,11 +72,11 @@ def setUpClass(cls): node.SetSolutionStepValue(Kratos.TEMPERATURE, -2.5) cls.temperature_control.Initialize() - cls.initial_temperature = Kratos.Expression.NodalExpression(cls.model_part) - Kratos.Expression.VariableExpressionIO.Read(cls.initial_temperature, Kratos.TEMPERATURE, 1) + cls.initial_temperature = Kratos.TensorAdaptors.HistoricalVariableTensorAdaptor(cls.model_part.Nodes, Kratos.TEMPERATURE) + cls.initial_temperature.CollectData() def setUp(self) -> None: - Kratos.Expression.VariableExpressionIO.Write(self.initial_temperature, Kratos.TEMPERATURE, 1) + self.initial_temperature.CollectData() @classmethod def tearDownClass(cls): @@ -88,17 +89,18 @@ def test_GetPhysicalKratosVariables(self): def test_GetControlField(self): control_field = self.temperature_control.GetControlField() - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(control_field), 0.0, 4) + self.assertAlmostEqual(np.linalg.norm(control_field.data), 0.0, 4) def test_GetPhysicalField(self): temperature_field = self.temperature_control.GetPhysicalField() - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(temperature_field), 7.5, 4) + self.assertAlmostEqual(np.linalg.norm(temperature_field.data), 7.5, 4) def test_MapGradient(self): physical_gradient = self.temperature_control.GetEmptyField() for node in physical_gradient.GetContainer(): node.SetValue(KratosSM.TEMPERATURE_SENSITIVITY, 1) - Kratos.Expression.VariableExpressionIO.Read(physical_gradient, KratosSM.TEMPERATURE_SENSITIVITY, 0) + Kratos.TensorAdaptors.VariableTensorAdaptor(physical_gradient, KratosSM.TEMPERATURE_SENSITIVITY, copy=False).CollectData() + mapped_gradient = self.temperature_control.MapGradient({Kratos.TEMPERATURE: physical_gradient}) # physical = -2.5 # ProjectBackward: phi = 0.5 - sin(asin(1-2*(physical - min)/delta)/3) = 0.3263518223 @@ -107,24 +109,24 @@ def test_MapGradient(self): # BackwardFilterIntegratedField: d_J/d_physical * d_physical/d_phi -> d_J/d_control (mapped gradient) # For Integrated type: domain_size (of node_1) = element_area / num_nodes = 0.125 / 3 = 0.0416667 # BackwardFilterIntegratedField: (1 * 13.19077862357725) / 0.0416667 = 316.57868697 (mapped gradient) - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(mapped_gradient), 316.57868697, 4) + self.assertAlmostEqual(np.linalg.norm(mapped_gradient.data, ord=np.inf), 316.57868697, 4) def test_Update(self): update_field = self.temperature_control.GetEmptyField() - Kratos.Expression.LiteralExpressionIO.SetData(update_field, 0.25) + update_field.data[:] = 0.25 temperature_field = self.temperature_control.GetPhysicalField() control_field = self.temperature_control.GetControlField() self.temperature_control.Update(update_field) control_field = self.temperature_control.GetControlField() temperature_field = self.temperature_control.GetPhysicalField() - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(control_field), 0.25, 4) + self.assertAlmostEqual(np.linalg.norm(control_field.data, ord=np.inf), 0.25, 4) # ForwardFilter: control_update -> phi_update (Here, filter radius ~ 0. Therefore, both are the same = 0.25) # physical = -2.5 # phi = 0.5 - sin(asin(1-2*(physical - min)/delta)/3) = 0.3263518223 # phi_updated = phi_current + phi_update = 0.3263518223 + 0.25 = 0.5763518223 # ProjectForward: phi_updated -> physical_updated # physical_updated = physical_min + phi_updated²*(3 - 2*phi_updated)* delta = 1.136375322 - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(temperature_field), 1.136375322, 6) + self.assertAlmostEqual(np.linalg.norm(temperature_field.data, ord=np.inf), 1.136375322, 6) class TestDataValuesControl_condition(kratos_unittest.TestCase): @classmethod @@ -188,11 +190,11 @@ def setUpClass(cls): condition.SetValue(Kratos.PRESSURE, -2.5) cls.pressure_control.Initialize() - cls.initial_pressure = Kratos.Expression.ConditionExpression(cls.model_part) - Kratos.Expression.VariableExpressionIO.Read(cls.initial_pressure, Kratos.PRESSURE) + cls.initial_pressure = Kratos.TensorAdaptors.VariableTensorAdaptor(cls.model_part.Conditions, Kratos.PRESSURE) + cls.initial_pressure.CollectData() def setUp(self) -> None: - Kratos.Expression.VariableExpressionIO.Write(self.initial_pressure, Kratos.PRESSURE) + self.initial_pressure.CollectData() @classmethod def tearDownClass(cls): @@ -205,17 +207,17 @@ def test_GetPhysicalKratosVariables(self): def test_GetControlField(self): control_field = self.pressure_control.GetControlField() - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(control_field), 0.0, 4) + self.assertAlmostEqual(np.linalg.norm(control_field.data, ord=np.inf), 0.0, 4) def test_GetPhysicalField(self): pressure_field = self.pressure_control.GetPhysicalField() - self.assertAlmostEqual(Kratos.Expression.Utils.NormL2(pressure_field), 3.535533906, 4) + self.assertAlmostEqual(np.linalg.norm(pressure_field.data), 3.535533906, 4) def test_MapGradient(self): physical_gradient = self.pressure_control.GetEmptyField() for condition in physical_gradient.GetContainer(): condition.SetValue(KratosSM.PRESSURE_SENSITIVITY, 1) - Kratos.Expression.VariableExpressionIO.Read(physical_gradient, KratosSM.PRESSURE_SENSITIVITY) + Kratos.TensorAdaptors.VariableTensorAdaptor(physical_gradient, KratosSM.PRESSURE_SENSITIVITY, copy=False).CollectData() mapped_gradient = self.pressure_control.MapGradient({Kratos.PRESSURE: physical_gradient}) # physical = -2.5 # ProjectBackward: phi = 0.5 - sin(asin(1-2*(physical - min)/delta)/3) = 0.3263518223 @@ -224,24 +226,24 @@ def test_MapGradient(self): # BackwardFilterIntegratedField: d_J/d_physical * d_physical/d_phi -> d_J/d_control (mapped gradient) # For Integrated type: domain_size (of condition_1) = condition_area = 0.25 # BackwardFilterIntegratedField: (1 * 13.19077862357725) / 0.25 = 52.76311449 (mapped gradient) - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(mapped_gradient), 52.76311449, 4) + self.assertAlmostEqual(np.linalg.norm(mapped_gradient.data, ord=np.inf), 52.76311449, 4) def test_Update(self): update_field = self.pressure_control.GetEmptyField() - Kratos.Expression.LiteralExpressionIO.SetData(update_field, 0.25) + update_field.data[:] = 0.25 pressure_field = self.pressure_control.GetPhysicalField() control_field = self.pressure_control.GetControlField() self.pressure_control.Update(update_field) control_field = self.pressure_control.GetControlField() pressure_field = self.pressure_control.GetPhysicalField() - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(control_field), 0.25, 4) + self.assertAlmostEqual(np.linalg.norm(control_field.data, ord=np.inf), 0.25, 4) # ForwardFilter: control_update -> phi_update (Here, filter radius ~ 0. Therefore, both are the same = 0.25) # physical = -2.5 # phi = 0.5 - sin(asin(1-2*(physical - min)/delta)/3) = 0.3263518223 # phi_updated = phi_current + phi_update = 0.3263518223 + 0.25 = 0.5763518223 # ProjectForward: phi_updated -> physical_updated # physical_updated = physical_min + phi_updated²*(3 - 2*phi_updated)* delta = 1.136375322 - self.assertAlmostEqual(Kratos.Expression.Utils.NormInf(pressure_field), 1.136375322, 6) + self.assertAlmostEqual(np.linalg.norm(pressure_field.data, ord=np.inf), 1.136375322, 6) if __name__ == "__main__": kratos_unittest.main() \ No newline at end of file From 5c608186b699c23887bc08976e63d2ab764560c6 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Tue, 17 Feb 2026 14:00:48 +0100 Subject: [PATCH 096/116] update response to TA --- .../controls/data_values_control.py | 4 +- .../controls/material_properties_control.py | 69 ++++++++++--------- .../responses/damage_detection_response.py | 21 +++--- .../responses/pressure_detection_response.py | 1 - .../temperature_detection_response.py | 1 - .../response_sensitivity_analysis.py | 13 ++-- .../response_sensitivity_interface.py | 2 - ...ensor_sensitivity_adjoint_static_solver.py | 2 - .../system_identification_static_analysis.py | 2 - .../tests/responses/test_damage_response.py | 4 +- .../tests/responses/test_pressure_response.py | 4 +- .../responses/test_temperature_response.py | 4 +- 12 files changed, 59 insertions(+), 68 deletions(-) diff --git a/applications/SystemIdentificationApplication/python_scripts/controls/data_values_control.py b/applications/SystemIdentificationApplication/python_scripts/controls/data_values_control.py index 4b4a9ffa9da5..8db631a0832b 100644 --- a/applications/SystemIdentificationApplication/python_scripts/controls/data_values_control.py +++ b/applications/SystemIdentificationApplication/python_scripts/controls/data_values_control.py @@ -156,7 +156,7 @@ def MapGradient(self, physical_gradient_variable_tensor_adaptor_map: 'dict[Suppo physical_gradient = physical_gradient_variable_tensor_adaptor_map[self.controlled_physical_variable] if physical_gradient.GetContainer() != self.GetEmptyField().GetContainer(): - raise RuntimeError(f"Gradients for the required element container not found for control \"{self.GetName()}\". [ required model part name: {self.primal_model_part.FullName()}, given model part name: {physical_gradient.GetModelPart().FullName()} ]") + raise RuntimeError(f"Gradients for the required element container not found for control \"{self.GetName()}\". [ required model part name: {self.primal_model_part.FullName()} ]") # dj/dE -> physical_gradient # dj/dphi = dj/dphysical * dphysical/dphi @@ -166,7 +166,7 @@ def MapGradient(self, physical_gradient_variable_tensor_adaptor_map: 'dict[Suppo def Update(self, new_control_field: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> bool: if new_control_field.GetContainer() != self.GetEmptyField().GetContainer(): - raise RuntimeError(f"Updates for the required element container not found for control \"{self.GetName()}\". [ required model part name: {self.primal_model_part.FullName()}, given model part name: {control_field.GetModelPart().FullName()} ]") + raise RuntimeError(f"Updates for the required element container not found for control \"{self.GetName()}\". [ required model part name: {self.primal_model_part.FullName()} ]") update = new_control_field.Clone() update.data[:] -= self.control_phi_field.data diff --git a/applications/SystemIdentificationApplication/python_scripts/controls/material_properties_control.py b/applications/SystemIdentificationApplication/python_scripts/controls/material_properties_control.py index cfc8e6e19a32..17d6e1b28e99 100644 --- a/applications/SystemIdentificationApplication/python_scripts/controls/material_properties_control.py +++ b/applications/SystemIdentificationApplication/python_scripts/controls/material_properties_control.py @@ -1,18 +1,16 @@ -import math +import math, numpy from typing import Optional import KratosMultiphysics as Kratos import KratosMultiphysics.OptimizationApplication as KratosOA import KratosMultiphysics.SystemIdentificationApplication as KratosSI from KratosMultiphysics.OptimizationApplication.controls.control import Control -from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import ContainerExpressionTypes from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes -from KratosMultiphysics.OptimizationApplication.utilities.helper_utilities import IsSameContainerExpression from KratosMultiphysics.OptimizationApplication.utilities.model_part_utilities import ModelPartOperation from KratosMultiphysics.OptimizationApplication.utilities.logger_utilities import TimeLogger from KratosMultiphysics.OptimizationApplication.utilities.component_data_view import ComponentDataView from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem -from KratosMultiphysics.SystemIdentificationApplication.utilities.expression_utils import ExpressionBoundingManager +from KratosMultiphysics.SystemIdentificationApplication.utilities.tensor_adaptor_utils import TensorAdaptorBoundingManager from KratosMultiphysics.OptimizationApplication.filtering.filter import Factory as FilterFactory def Factory(model: Kratos.Model, parameters: Kratos.Parameters, optimization_problem: OptimizationProblem) -> Control: @@ -92,8 +90,8 @@ def __init__(self, name: str, model: Kratos.Model, parameters: Kratos.Parameters control_variable_bounds = parameters["control_variable_bounds"].GetVector() # use the clamper in the unit interval - self.interval_bounder = ExpressionBoundingManager(control_variable_bounds) - self.clamper = KratosSI.ElementSmoothClamper(0, 1) + self.interval_bounder = TensorAdaptorBoundingManager(control_variable_bounds) + self.clamper = KratosSI.SmoothClamper(0, 1) def Initialize(self) -> None: self.primal_model_part = self.primal_model_part_operation.GetModelPart() @@ -118,12 +116,13 @@ def Initialize(self) -> None: physical_field = self.GetPhysicalField() # get the phi field which is in [0, 1] range - self.physical_phi_field = self.clamper.ProjectBackward(self.interval_bounder.GetBoundedExpression(physical_field)) + self.physical_phi_field = self.clamper.ProjectBackward(self.interval_bounder.GetBoundedTensorAdaptor(physical_field)) # compute the control phi field self.control_phi_field = self.filter.UnfilterField(self.physical_phi_field) - self.physical_phi_derivative_field = self.clamper.CalculateForwardProjectionGradient(self.physical_phi_field) * self.interval_bounder.GetBoundGap() + self.physical_phi_derivative_field = self.clamper.CalculateForwardProjectionGradient(self.physical_phi_field) + self.physical_phi_derivative_field.data[:] *= self.interval_bounder.GetBoundGap() self._UpdateAndOutputFields(self.GetEmptyField()) @@ -136,44 +135,47 @@ def Finalize(self) -> None: def GetPhysicalKratosVariables(self) -> 'list[SupportedSensitivityFieldVariableTypes]': return [self.controlled_physical_variable] - def GetEmptyField(self) -> ContainerExpressionTypes: - field = Kratos.Expression.ElementExpression(self.primal_model_part) - Kratos.Expression.LiteralExpressionIO.SetData(field, 0.0) + def GetEmptyField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + field = Kratos.TensorAdaptors.VariableTensorAdaptor(self.primal_model_part.Elements, self.controlled_physical_variable) + field.data[:] = 0.0 return field - def GetControlField(self) -> ContainerExpressionTypes: - return self.control_phi_field + def GetControlField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + return self.control_phi_field.Clone() - def GetPhysicalField(self) -> ContainerExpressionTypes: - physical_thickness_field = Kratos.Expression.ElementExpression(self.primal_model_part) - KratosOA.PropertiesVariableExpressionIO.Read(physical_thickness_field, self.controlled_physical_variable) + def GetPhysicalField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: + physical_thickness_field = KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(self.primal_model_part.Elements, self.controlled_physical_variable) + physical_thickness_field.CollectData() return physical_thickness_field - def MapGradient(self, physical_gradient_variable_container_expression_map: 'dict[SupportedSensitivityFieldVariableTypes, ContainerExpressionTypes]') -> ContainerExpressionTypes: + def MapGradient(self, physical_gradient_variable_tensor_adaptor_map: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleTensorAdaptor]') -> Kratos.TensorAdaptors.DoubleTensorAdaptor: with TimeLogger("ShellThicknessControl::MapGradient", None, "Finished",False): - keys = physical_gradient_variable_container_expression_map.keys() + keys = physical_gradient_variable_tensor_adaptor_map.keys() if len(keys) != 1: raise RuntimeError(f"Provided more than required gradient fields for control \"{self.GetName()}\". Following are the variables:\n\t" + "\n\t".join([k.Name() for k in keys])) if self.controlled_physical_variable not in keys: raise RuntimeError(f"The required gradient for control \"{self.GetName()}\" w.r.t. {self.controlled_physical_variable.Name()} not found. Followings are the variables:\n\t" + "\n\t".join([k.Name() for k in keys])) - physical_gradient = physical_gradient_variable_container_expression_map[self.controlled_physical_variable] - if not IsSameContainerExpression(physical_gradient, self.GetEmptyField()): - raise RuntimeError(f"Gradients for the required element container not found for control \"{self.GetName()}\". [ required model part name: {self.primal_model_part.FullName()}, given model part name: {physical_gradient.GetModelPart().FullName()} ]") + physical_gradient = physical_gradient_variable_tensor_adaptor_map[self.controlled_physical_variable] + if physical_gradient.GetContainer() != self.primal_model_part.Elements: + raise RuntimeError(f"Gradients for the required element container not found for control \"{self.GetName()}\". [ required model part name: {self.primal_model_part.FullName()} ]") # dj/dE -> physical_gradient # dj/dphi = dj/dphysical * dphysical/dphi - return self.filter.BackwardFilterIntegratedField(physical_gradient * self.physical_phi_derivative_field) + dj_dphi = physical_gradient.Clone() + dj_dphi.data[:] *= self.physical_phi_derivative_field.data + return self.filter.BackwardFilterIntegratedField(dj_dphi) - def Update(self, new_control_field: ContainerExpressionTypes) -> bool: - if not IsSameContainerExpression(new_control_field, self.GetEmptyField()): - raise RuntimeError(f"Updates for the required element container not found for control \"{self.GetName()}\". [ required model part name: {self.primal_model_part.FullName()}, given model part name: {control_field.GetModelPart().FullName()} ]") + def Update(self, new_control_field: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> bool: + if new_control_field.GetContainer() != self.primal_model_part.Elements: + raise RuntimeError(f"Updates for the required element container not found for control \"{self.GetName()}\". [ required model part name: {self.primal_model_part.FullName()} ]") - update = new_control_field - self.control_phi_field - if not math.isclose(Kratos.Expression.Utils.NormL2(update), 0.0, abs_tol=1e-16): + update = new_control_field.Clone() + update.data[:] -= self.control_phi_field.data + if not math.isclose(numpy.linalg.norm(update.data), 0.0, abs_tol=1e-16): with TimeLogger(self.__class__.__name__, f"Updating {self.GetName()}...", f"Finished updating of {self.GetName()}.",False): # update the control thickness field - self.control_phi_field = new_control_field + self.control_phi_field.data[:] = new_control_field.data # now update the physical field self._UpdateAndOutputFields(update) @@ -182,22 +184,23 @@ def Update(self, new_control_field: ContainerExpressionTypes) -> bool: return True return False - def _UpdateAndOutputFields(self, update: ContainerExpressionTypes) -> None: + def _UpdateAndOutputFields(self, update: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> None: # filter the control field filtered_phi_field_update = self.filter.ForwardFilterField(update) - self.physical_phi_field = Kratos.Expression.Utils.Collapse(self.physical_phi_field + filtered_phi_field_update) + self.physical_phi_field.data[:] += filtered_phi_field_update.data # project forward the filtered thickness field to get clamped physical field - physical_field = self.interval_bounder.GetUnboundedExpression(self.clamper.ProjectForward(self.physical_phi_field)) + physical_field = self.interval_bounder.GetUnboundedTensorAdaptor(self.clamper.ProjectForward(self.physical_phi_field)) # now update physical field - KratosOA.PropertiesVariableExpressionIO.Write(physical_field, self.controlled_physical_variable) + KratosOA.TensorAdaptors.PropertiesVariableTensorAdaptor(physical_field, self.controlled_physical_variable, copy=False).StoreData() if self.consider_recursive_property_update: KratosOA.OptimizationUtils.UpdatePropertiesVariableWithRootValueRecursively(physical_field.GetContainer(), self.controlled_physical_variable) # compute and store projection derivatives for consistent filtering of the sensitivities # this is dphi/dphysical -> physical_phi_derivative_field - self.physical_phi_derivative_field = self.clamper.CalculateForwardProjectionGradient(self.physical_phi_field) * self.interval_bounder.GetBoundGap() + self.physical_phi_derivative_field = self.clamper.CalculateForwardProjectionGradient(self.physical_phi_field) + self.physical_phi_derivative_field.data[:] *= self.interval_bounder.GetBoundGap() # now output the fields un_buffered_data = ComponentDataView(self, self.optimization_problem).GetUnBufferedData() diff --git a/applications/SystemIdentificationApplication/python_scripts/responses/damage_detection_response.py b/applications/SystemIdentificationApplication/python_scripts/responses/damage_detection_response.py index 324ebcdea18d..dccfa448bd75 100644 --- a/applications/SystemIdentificationApplication/python_scripts/responses/damage_detection_response.py +++ b/applications/SystemIdentificationApplication/python_scripts/responses/damage_detection_response.py @@ -1,13 +1,10 @@ from typing import Optional import csv -from pathlib import Path import KratosMultiphysics as Kratos -import KratosMultiphysics.OptimizationApplication as KratosOA import KratosMultiphysics.SystemIdentificationApplication as KratosDT from KratosMultiphysics.OptimizationApplication.responses.response_function import ResponseFunction from KratosMultiphysics.OptimizationApplication.responses.response_function import SupportedSensitivityFieldVariableTypes -from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes from KratosMultiphysics.OptimizationApplication.utilities.model_part_utilities import ModelPartOperation from KratosMultiphysics.OptimizationApplication.execution_policies.execution_policy_decorator import ExecutionPolicyDecorator from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem @@ -134,11 +131,11 @@ def CalculateValue(self) -> float: return result - def CalculateGradient(self, physical_variable_collective_expressions: 'dict[SupportedSensitivityFieldVariableTypes, KratosOA.CollectiveExpression]') -> None: + def CalculateGradient(self, physical_variable_combined_tensor_adaptor: 'dict[SupportedSensitivityFieldVariableTypes, Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor]') -> None: # make everything zeros - for physical_variable, collective_expression in physical_variable_collective_expressions.items(): - for container_expression in collective_expression.GetContainerExpressions(): - Kratos.Expression.LiteralExpressionIO.SetDataToZero(container_expression, physical_variable) + for physical_variable, cta in physical_variable_combined_tensor_adaptor.items(): + cta.data[:] = 0.0 + Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(cta, perform_store_data_recursively=False, copy=False).StoreData() # now compute sensitivities for each test scenario for exec_policy, sensor_measurement_data_file_name, test_case_weight in self.list_of_test_analysis_data: @@ -150,13 +147,13 @@ def CalculateGradient(self, physical_variable_collective_expressions: 'dict[Supp self.adjoint_analysis._GetSolver().GetComputingModelPart().ProcessInfo[Kratos.STEP] = self.optimization_problem.GetStep() self.adjoint_analysis.CalculateGradient(self.damage_response_function) - for physical_variable, collective_expression in physical_variable_collective_expressions.items(): + for physical_variable, cta in physical_variable_combined_tensor_adaptor.items(): sensitivity_variable = Kratos.KratosGlobals.GetVariable(Kratos.SensitivityUtilities.GetSensitivityVariableName(physical_variable)) - for container_expression in collective_expression.GetContainerExpressions(): - current_gradient = container_expression.Clone() + for ta in cta.GetTensorAdaptors(): + current_gradient = ta.Clone() self.adjoint_analysis.GetGradient(sensitivity_variable, current_gradient) - container_expression.SetExpression((container_expression.GetExpression() - current_gradient.GetExpression() * test_case_weight)) - container_expression.SetExpression(Kratos.Expression.Utils.Collapse(container_expression).GetExpression()) + ta.data[:] -= current_gradient.data[:] * test_case_weight + Kratos.TensorAdaptors.DoubleCombinedTensorAdaptor(cta, perform_collect_data_recursively=False, copy=False).CollectData() def __GetSensor(self, sensor_name: str) -> KratosDT.Sensors.Sensor: return self.sensor_name_dict[sensor_name] diff --git a/applications/SystemIdentificationApplication/python_scripts/responses/pressure_detection_response.py b/applications/SystemIdentificationApplication/python_scripts/responses/pressure_detection_response.py index dd1963e7c68c..7fe4fb16f902 100644 --- a/applications/SystemIdentificationApplication/python_scripts/responses/pressure_detection_response.py +++ b/applications/SystemIdentificationApplication/python_scripts/responses/pressure_detection_response.py @@ -1,7 +1,6 @@ import KratosMultiphysics as Kratos from KratosMultiphysics.OptimizationApplication.responses.response_function import ResponseFunction from KratosMultiphysics.OptimizationApplication.responses.response_function import SupportedSensitivityFieldVariableTypes -from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem from KratosMultiphysics.SystemIdentificationApplication.responses.damage_detection_response import DamageDetectionResponse diff --git a/applications/SystemIdentificationApplication/python_scripts/responses/temperature_detection_response.py b/applications/SystemIdentificationApplication/python_scripts/responses/temperature_detection_response.py index 23206ef3ece8..3924779fca10 100644 --- a/applications/SystemIdentificationApplication/python_scripts/responses/temperature_detection_response.py +++ b/applications/SystemIdentificationApplication/python_scripts/responses/temperature_detection_response.py @@ -1,7 +1,6 @@ import KratosMultiphysics as Kratos from KratosMultiphysics.OptimizationApplication.responses.response_function import ResponseFunction from KratosMultiphysics.OptimizationApplication.responses.response_function import SupportedSensitivityFieldVariableTypes -from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes from KratosMultiphysics.OptimizationApplication.utilities.optimization_problem import OptimizationProblem from KratosMultiphysics.SystemIdentificationApplication.responses.damage_detection_response import DamageDetectionResponse diff --git a/applications/SystemIdentificationApplication/python_scripts/sensor_sensitivity_solvers/response_sensitivity_analysis.py b/applications/SystemIdentificationApplication/python_scripts/sensor_sensitivity_solvers/response_sensitivity_analysis.py index 126fa07445e2..2543ea297458 100644 --- a/applications/SystemIdentificationApplication/python_scripts/sensor_sensitivity_solvers/response_sensitivity_analysis.py +++ b/applications/SystemIdentificationApplication/python_scripts/sensor_sensitivity_solvers/response_sensitivity_analysis.py @@ -3,7 +3,6 @@ import KratosMultiphysics as Kratos from KratosMultiphysics.analysis_stage import AnalysisStage -from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import ContainerExpressionTypes from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes class ResponseSensitivityAnalysis(AnalysisStage, abc.ABC): @@ -18,17 +17,17 @@ def CalculateGradient(self, response_function: Kratos.AdjointResponseFunction) - """ pass - def GetGradient(self, sensitivity_variable: SupportedSensitivityFieldVariableTypes, gradient_expression: ContainerExpressionTypes) -> None: - """Returns the gradients in the domain represented by gradient_expression container expression. + def GetGradient(self, sensitivity_variable: SupportedSensitivityFieldVariableTypes, gradient_tensor_adaptor: Kratos.TensorAdaptors.DoubleTensorAdaptor) -> None: + """Returns the gradients in the domain represented by gradient_tensor_adaptor tensor adaptor. Args: sensitivity_variable (SupportedSensitivityFieldVariableTypes): Sensitivity variable - gradient_expression (ContainerExpressionTypes): Container expression to hold the gradients. + gradient_tensor_adaptor (Kratos.TensorAdaptors.DoubleTensorAdaptor): TensorAdaptor to hold the gradients. """ - if isinstance(gradient_expression, Kratos.Expression.NodalExpression): - Kratos.Expression.VariableExpressionIO.Read(gradient_expression, sensitivity_variable, True) + if isinstance(gradient_tensor_adaptor.GetContainer(), Kratos.NodesArray): + Kratos.TensorAdaptors.HistoricalVariableTensorAdaptor(gradient_tensor_adaptor, sensitivity_variable, copy=False).CollectData() else: - Kratos.Expression.VariableExpressionIO.Read(gradient_expression, sensitivity_variable) + Kratos.TensorAdaptors.VariableTensorAdaptor(gradient_tensor_adaptor, sensitivity_variable, copy=False).CollectData() def GetProcessesOrder(self) -> 'list[str]': """The order of execution of the process categories. diff --git a/applications/SystemIdentificationApplication/python_scripts/sensor_sensitivity_solvers/response_sensitivity_interface.py b/applications/SystemIdentificationApplication/python_scripts/sensor_sensitivity_solvers/response_sensitivity_interface.py index 0abaceaead12..a279394577ff 100644 --- a/applications/SystemIdentificationApplication/python_scripts/sensor_sensitivity_solvers/response_sensitivity_interface.py +++ b/applications/SystemIdentificationApplication/python_scripts/sensor_sensitivity_solvers/response_sensitivity_interface.py @@ -1,7 +1,5 @@ import abc import KratosMultiphysics as Kratos -from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes -from KratosMultiphysics.SystemIdentificationApplication.utilities.expression_utils import ExpressionUnionType class ResponseSensitivityInterface(abc.ABC): @abc.abstractmethod diff --git a/applications/SystemIdentificationApplication/python_scripts/sensor_sensitivity_solvers/sensor_sensitivity_adjoint_static_solver.py b/applications/SystemIdentificationApplication/python_scripts/sensor_sensitivity_solvers/sensor_sensitivity_adjoint_static_solver.py index c37d46fb4768..9c14ad6fca47 100644 --- a/applications/SystemIdentificationApplication/python_scripts/sensor_sensitivity_solvers/sensor_sensitivity_adjoint_static_solver.py +++ b/applications/SystemIdentificationApplication/python_scripts/sensor_sensitivity_solvers/sensor_sensitivity_adjoint_static_solver.py @@ -1,8 +1,6 @@ import KratosMultiphysics as Kratos import KratosMultiphysics.SystemIdentificationApplication as KratosSI from KratosMultiphysics.StructuralMechanicsApplication.structural_mechanics_adjoint_static_solver import StructuralMechanicsAdjointStaticSolver -from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes -from KratosMultiphysics.SystemIdentificationApplication.utilities.expression_utils import ExpressionUnionType from KratosMultiphysics.SystemIdentificationApplication.sensor_sensitivity_solvers.response_sensitivity_interface import ResponseSensitivityInterface class SensorSensitivityAdjointStaticSolver(StructuralMechanicsAdjointStaticSolver, ResponseSensitivityInterface): diff --git a/applications/SystemIdentificationApplication/python_scripts/sensor_sensitivity_solvers/system_identification_static_analysis.py b/applications/SystemIdentificationApplication/python_scripts/sensor_sensitivity_solvers/system_identification_static_analysis.py index d0e6d0c193c6..d7857341f807 100644 --- a/applications/SystemIdentificationApplication/python_scripts/sensor_sensitivity_solvers/system_identification_static_analysis.py +++ b/applications/SystemIdentificationApplication/python_scripts/sensor_sensitivity_solvers/system_identification_static_analysis.py @@ -3,8 +3,6 @@ from KratosMultiphysics.SystemIdentificationApplication.sensor_sensitivity_solvers.response_sensitivity_analysis import ResponseSensitivityAnalysis from KratosMultiphysics.SystemIdentificationApplication.sensor_sensitivity_solvers.sensor_sensitivity_adjoint_static_solver import SensorSensitivityAdjointStaticSolver -from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import ContainerExpressionTypes -from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes def Factory(model: Kratos.Model, parameters: Kratos.Parameters, _): return SystemIdentificationStaticAnalysis(model, parameters["settings"]) diff --git a/applications/SystemIdentificationApplication/tests/responses/test_damage_response.py b/applications/SystemIdentificationApplication/tests/responses/test_damage_response.py index 802583fcdefb..0090bebedab3 100644 --- a/applications/SystemIdentificationApplication/tests/responses/test_damage_response.py +++ b/applications/SystemIdentificationApplication/tests/responses/test_damage_response.py @@ -144,7 +144,7 @@ def test_DamageResponse(self): response.CalculateGradient(var) - gradients = var[Kratos.YOUNG_MODULUS].Evaluate() + gradients = var[Kratos.YOUNG_MODULUS].data delta = 1e-8 for index, element in enumerate(model_part.Elements): @@ -175,7 +175,7 @@ def test_DamageResponse(self): response.CalculateGradient(var) - gradients = var[Kratos.YOUNG_MODULUS].Evaluate() + gradients = var[Kratos.YOUNG_MODULUS].data delta = 1e-8 for index, element in enumerate(model_part.Elements): diff --git a/applications/SystemIdentificationApplication/tests/responses/test_pressure_response.py b/applications/SystemIdentificationApplication/tests/responses/test_pressure_response.py index bfed805bdaf5..ea88bee114e0 100644 --- a/applications/SystemIdentificationApplication/tests/responses/test_pressure_response.py +++ b/applications/SystemIdentificationApplication/tests/responses/test_pressure_response.py @@ -148,7 +148,7 @@ def test_PressureResponse(self): response.CalculateGradient(var) - gradients = var[Kratos.PRESSURE].Evaluate() + gradients = var[Kratos.PRESSURE].data delta = 1e-5 for index, condition in enumerate(model_part.Conditions): @@ -183,7 +183,7 @@ def test_PressureResponse(self): response.CalculateGradient(var) - gradients = var[Kratos.PRESSURE].Evaluate() + gradients = var[Kratos.PRESSURE].data delta = 1e-5 for index, condition in enumerate(model_part.Conditions): diff --git a/applications/SystemIdentificationApplication/tests/responses/test_temperature_response.py b/applications/SystemIdentificationApplication/tests/responses/test_temperature_response.py index 4d99723ff077..029e3a978db2 100644 --- a/applications/SystemIdentificationApplication/tests/responses/test_temperature_response.py +++ b/applications/SystemIdentificationApplication/tests/responses/test_temperature_response.py @@ -145,7 +145,7 @@ def test_TemperatureResponse(self): response.CalculateGradient(var) - gradients = var[Kratos.TEMPERATURE].Evaluate() + gradients = var[Kratos.TEMPERATURE].data delta = 1e-5 for index, node in enumerate(model_part.Nodes): @@ -179,7 +179,7 @@ def test_TemperatureResponse(self): response.CalculateGradient(var) - gradients = var[Kratos.TEMPERATURE].Evaluate() + gradients = var[Kratos.TEMPERATURE].data delta = 1e-4 for index, node in enumerate(model_part.Nodes): From 8779b6da0bc8ff8f9ebc3c5e8509d46d9382fcb9 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya <7856520+sunethwarna@users.noreply.github.com> Date: Wed, 18 Feb 2026 08:00:21 +0100 Subject: [PATCH 097/116] Remove unused 'stride' parameter from lambdas --- .../filtering/neareset_entity_explicit_damping.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/OptimizationApplication/custom_utilities/filtering/neareset_entity_explicit_damping.cpp b/applications/OptimizationApplication/custom_utilities/filtering/neareset_entity_explicit_damping.cpp index ba193ae2e2b7..5def1a53c566 100644 --- a/applications/OptimizationApplication/custom_utilities/filtering/neareset_entity_explicit_damping.cpp +++ b/applications/OptimizationApplication/custom_utilities/filtering/neareset_entity_explicit_damping.cpp @@ -121,7 +121,7 @@ void NearestEntityExplicitDamping::Update() } if (damped_entities.empty()) { - IndexPartition(r_container.size()).for_each([this, stride, i_comp](const auto Index) { + IndexPartition(r_container.size()).for_each([this, i_comp](const auto Index) { this->mDampingCoefficients(Index, i_comp) = 1.0; }); } else { @@ -185,7 +185,7 @@ void NearestEntityExplicitDamping::NearestEntityExplicitDamping: rOutput.clear(); - IndexPartition(number_of_entities).for_each([this, &rOutput, stride, ComponentIndex, number_of_entities](const auto Index) { + IndexPartition(number_of_entities).for_each([this, &rOutput, ComponentIndex, number_of_entities](const auto Index) { *(rOutput.data().begin() + Index * number_of_entities + Index) = this->mDampingCoefficients(Index, ComponentIndex); }); From 98e1ac8d8cad172a060562502f02fd94044506a6 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya <7856520+sunethwarna@users.noreply.github.com> Date: Wed, 18 Feb 2026 08:33:47 +0100 Subject: [PATCH 098/116] Fix lambda capture in for_each loop --- .../filtering/neareset_entity_explicit_damping.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/OptimizationApplication/custom_utilities/filtering/neareset_entity_explicit_damping.cpp b/applications/OptimizationApplication/custom_utilities/filtering/neareset_entity_explicit_damping.cpp index 5def1a53c566..7a2dc176636b 100644 --- a/applications/OptimizationApplication/custom_utilities/filtering/neareset_entity_explicit_damping.cpp +++ b/applications/OptimizationApplication/custom_utilities/filtering/neareset_entity_explicit_damping.cpp @@ -130,7 +130,7 @@ void NearestEntityExplicitDamping::Update() const auto& kernel_function = *mpKernelFunction; // now calculate the damping for each entity - IndexPartition(r_container.size()).for_each([this, &r_container, &p_search_tree, &kernel_function, &radius_view, stride, i_comp](const auto Index){ + IndexPartition(r_container.size()).for_each([this, &r_container, &p_search_tree, &kernel_function, &radius_view, i_comp](const auto Index){ EntityPointType entity_point(*(r_container.begin() + Index), Index); const auto radius = radius_view[Index]; From 309ac19126269ea139c1e920ea1023c31501e352 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Thu, 19 Feb 2026 08:34:43 +0100 Subject: [PATCH 099/116] add skip for VTU future --- .../test_optimization_problem_vtu_output_process.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/applications/OptimizationApplication/tests/process_tests/test_optimization_problem_vtu_output_process.py b/applications/OptimizationApplication/tests/process_tests/test_optimization_problem_vtu_output_process.py index 8446a7ac1fd1..f0b46c94e48c 100644 --- a/applications/OptimizationApplication/tests/process_tests/test_optimization_problem_vtu_output_process.py +++ b/applications/OptimizationApplication/tests/process_tests/test_optimization_problem_vtu_output_process.py @@ -14,6 +14,8 @@ from KratosMultiphysics.OptimizationApplication.utilities.union_utilities import SupportedSensitivityFieldVariableTypes from KratosMultiphysics.compare_two_files_check_process import CompareTwoFilesCheckProcess + +@kratos_unittest.skipUnless(hasattr(Kratos, "Future"), "Kratos is not compiled with KRATOS_FUTURE = ON.") class TestOptimizationProblemVtuOutputProcess(kratos_unittest.TestCase): class DummyResponseFunction(ResponseFunction): def __init__(self, response_name: str, model_part: Kratos.ModelPart) -> None: From f6105c465da8cb06c81d3e1132cce79a8cbeaac0 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 20 Feb 2026 07:50:13 +0100 Subject: [PATCH 100/116] port vtu_output from future --- kratos/future/input_output/vtu_output.cpp | 1743 ----------------- kratos/future/input_output/vtu_output.h | 383 ---- kratos/input_output/vtu_output.cpp | 2096 +++++++++++++++------ kratos/input_output/vtu_output.h | 389 ++-- 4 files changed, 1759 insertions(+), 2852 deletions(-) delete mode 100644 kratos/future/input_output/vtu_output.cpp delete mode 100644 kratos/future/input_output/vtu_output.h diff --git a/kratos/future/input_output/vtu_output.cpp b/kratos/future/input_output/vtu_output.cpp deleted file mode 100644 index d39c067f719e..000000000000 --- a/kratos/future/input_output/vtu_output.cpp +++ /dev/null @@ -1,1743 +0,0 @@ -// | / | -// ' / __| _` | __| _ \ __| -// . \ | ( | | ( |\__ ` -// _|\_\_| \__,_|\__|\___/ ____/ -// Multi-Physics -// -// License: BSD License -// Kratos default license: kratos/license.txt -// -// Main authors: Suneth Warnakulasuriya -// - -// System includes -#include -#include -#include -#include - -// External includes - -// Project includes -#include "includes/data_communicator.h" -#include "input_output/base_64_encoded_output.h" -#include "input_output/vtk_definitions.h" -#include "tensor_adaptors/flags_tensor_adaptor.h" -#include "tensor_adaptors/historical_variable_tensor_adaptor.h" -#include "tensor_adaptors/node_position_tensor_adaptor.h" -#include "tensor_adaptors/variable_tensor_adaptor.h" -#include "utilities/container_io_utils.h" -#include "utilities/data_type_traits.h" -#include "utilities/parallel_utilities.h" -#include "utilities/reduction_utilities.h" -#include "utilities/string_utilities.h" -#include "future/utilities/xml_utilities/xml_appended_data_element_wrapper.h" -#include "future/utilities/xml_utilities/xml_elements_array.h" -#include "future/utilities/xml_utilities/xml_in_place_data_element_wrapper.h" -#include "future/utilities/xml_utilities/xml_utils.h" - -// Include base h -#include "vtu_output.h" - -namespace Kratos::Future { - -namespace { - -std::string GetEndianness() -{ - int i = 0x0001; - - if (*reinterpret_cast(&i) != 0) { - return "LittleEndian"; - } else { - return "BigEndian"; - } -} - -template -void CheckDataArrayName( - const std::string& rName, - const Globals::DataLocation& rLocation, - const VtuOutput::DataList& rList) -{ - KRATOS_TRY - - KRATOS_ERROR_IF(rList[static_cast(rLocation)].find(rName) != rList[static_cast(rLocation)].end()) - << "Found an existing data array with the same name = \"" << rName << "\".\n"; - - KRATOS_CATCH(""); -} - -void CheckDataArrayName( - const std::string& rName, - const Globals::DataLocation& rLocation, - const VtuOutput::UnstructuredGridData& rUnstructuredGridData) -{ - KRATOS_TRY - - bool found_existing_name = false; - switch (rLocation) { - case Globals::DataLocation::NodeHistorical: - case Globals::DataLocation::NodeNonHistorical: - // The following code block will be executed for Globals::DataLocation::NodeHistorical and Globals::DataLocation::NodeNonHistorical. - found_existing_name = rUnstructuredGridData.mMapOfPointTensorAdaptors.find(rName) != rUnstructuredGridData.mMapOfPointTensorAdaptors.end(); - break; - case Globals::DataLocation::Condition: - case Globals::DataLocation::Element: - // The following code block will be executed for Globals::DataLocation::Condition and Globals::DataLocation::Element. - found_existing_name = rUnstructuredGridData.mMapOfCellTensorAdaptors.find(rName) != rUnstructuredGridData.mMapOfCellTensorAdaptors.end(); - break; - default: - KRATOS_ERROR << "Unsupported data location type."; - } - - KRATOS_ERROR_IF(found_existing_name) - << "Found an existing data array with the same name = \"" << rName << "\".\n"; - - KRATOS_CATCH(""); -} - -void CheckDataArrayName( - const std::string& rName, - const Globals::DataLocation& rLocation, - const std::vector& rListOfUnstructuredGridData) -{ - KRATOS_TRY - - for (const auto& r_model_part_data : rListOfUnstructuredGridData) { - switch (rLocation) { - case Globals::DataLocation::NodeHistorical: - case Globals::DataLocation::NodeNonHistorical: - // The following code block will be executed for Globals::DataLocation::NodeHistorical and Globals::DataLocation::NodeNonHistorical. - if (r_model_part_data.UsePointsForDataFieldOutput) { - CheckDataArrayName(rName, rLocation, r_model_part_data); - } - break; - default: - CheckDataArrayName(rName, rLocation, r_model_part_data); - } - } - - KRATOS_CATCH(""); -} - -std::string GetEntityName(const std::optional& pCellContainer) -{ - if (pCellContainer.has_value()) { - return std::visit([](auto p_cell_container) { - using container_type = BareType; - return ModelPart::Container::GetEntityName(); - }, pCellContainer.value()); - } else { - return "node"; - } -} - -void CopyAttributes( - const XmlElement& rSource, - XmlElement& rDestination) -{ - for (const auto& [attribute, value] : rSource.GetAttributes()) { - rDestination.AddAttribute(attribute, value); - } -} - -template -NDDataPointerType GetWritingNDData( - const std::vector& rWritingIndices, - NDDataPointerType pNDData) -{ - KRATOS_TRY - - const auto& origin_shape = pNDData->Shape(); - - KRATOS_ERROR_IF(origin_shape.size() == 0) - << "NDData shape should have at least one dimension representing number of entities [ nd data = " - << *pNDData << " ].\n"; - - if (rWritingIndices.size() == origin_shape[0]) { - // number of writing indices are same as the first dimension of the NdData, hence - // there is nothing to be ignored from this data set. Returning the original - return pNDData; - } else { - // now there is a mismatch between number of writing indices and the number of entities represented by the pNDData. - // Hence we continue with copying data. - - // data type of the NDData, may be unsigned char, int, bool, double - using data_type = typename BareType::DataType; - - // compute number of components for each entity. - const auto number_of_components = std::accumulate(origin_shape.begin() + 1, origin_shape.end(), 1u, std::multiplies{}); - - // construct the new NDData holder having only the data from writing indices. - DenseVector destination_shape(origin_shape); - destination_shape[0] = rWritingIndices.size(); - auto p_destination_nd_data = Kratos::make_shared>(destination_shape); - - // get spans - const auto& origin_span = pNDData->ViewData(); - auto destination_span = p_destination_nd_data->ViewData(); - - // now copy the data - IndexPartition(rWritingIndices.size()).for_each([&origin_span, &destination_span, &rWritingIndices, number_of_components](const auto Index) { - auto orig_itr = origin_span.begin() + rWritingIndices[Index] * number_of_components; - auto dest_itr = destination_span.begin() + Index * number_of_components; - std::copy(orig_itr, orig_itr + number_of_components, dest_itr); - }); - - return p_destination_nd_data; - } - - KRATOS_CATCH(""); -} - -template -NDData::Pointer GetGeometryTypes( - std::vector& rWritingIndices, - const TContainerType& rContainer, - const IndexType EchoLevel) -{ - auto p_geometry_types = Kratos::make_shared>(DenseVector(1, rContainer.size())); - auto span = p_geometry_types->ViewData(); - - DenseVector ignored_indices(rContainer.size(), 0); - - IndexPartition(rContainer.size()).for_each([&span, &rContainer, &ignored_indices, EchoLevel](const IndexType Index) { - - const auto p_itr = VtkDefinitions::KratosVtkGeometryTypes.find((rContainer.begin() + Index)->GetGeometry().GetGeometryType()); - if (p_itr != VtkDefinitions::KratosVtkGeometryTypes.end()) { - *(span.begin() + Index) = static_cast(p_itr->second); - } else { - ignored_indices[Index] = 1; - KRATOS_WARNING_IF("VtuOutput", EchoLevel > 1) - << "Skipping unsupported geometry type in " - << ModelPart::Container::GetEntityName() - << " with id " << (rContainer.begin() + Index)->Id() << ".\n"; - } - }); - - // fill in the writing indices - rWritingIndices.reserve(rContainer.size()); - for (IndexType i = 0; i < rContainer.size(); ++i) { - if (ignored_indices[i] != 1) { - rWritingIndices.push_back(i); - } - } - - return p_geometry_types; -} - -template -NDData::Pointer GetOffsets( - const std::vector& rWritingIndices, - const TContainerType& rContainer) -{ - auto p_offsets = Kratos::make_shared>(DenseVector(1, rWritingIndices.size())); - auto data_itr = p_offsets->ViewData().begin(); - - int total_offset = 0; - for (IndexType i = 0; i < rWritingIndices.size(); ++i) { - total_offset += (rContainer.begin() + rWritingIndices[i])->GetGeometry().size(); - data_itr[i] = total_offset; - } - - return p_offsets; -} - -template -NDData::Pointer GetConnectivities( - const NDData& rOffsets, - const TContainerType& rContainer, - const std::unordered_map& rKratosVtuIndicesMap, - const std::vector& rWritingIndices) -{ - if (rOffsets.Size() == 0) { - return Kratos::make_shared>(DenseVector(1, 0)); - } - - const auto offsets_span = rOffsets.ViewData(); - auto p_connectivities = Kratos::make_shared>(DenseVector(1, offsets_span.back())); - auto connectivities_span = p_connectivities->ViewData(); - - IndexPartition(rWritingIndices.size()).for_each([&connectivities_span, &offsets_span, &rContainer, &rKratosVtuIndicesMap, &rWritingIndices](const IndexType Index) { - const auto& r_geometry = (rContainer.begin() + rWritingIndices[Index])->GetGeometry(); - auto entity_data_begin_itr = connectivities_span.begin() + offsets_span[Index] - r_geometry.size(); - - for (IndexType i_node = 0; i_node < r_geometry.size(); ++i_node) { - const auto p_itr = rKratosVtuIndicesMap.find(r_geometry[i_node].Id()); - if (p_itr != rKratosVtuIndicesMap.end()) { - entity_data_begin_itr[i_node] = p_itr->second; - } else { - KRATOS_ERROR << "Node with id " << r_geometry[i_node].Id() << " not found in nodes list."; - } - } - }); - - return p_connectivities; -} - -template -void AddConnectivityData( - XmlElementsArray& rCellElement, - std::vector& rWritingIndices, - const ModelPart::NodesContainerType& rNodes, - VtuOutput::CellContainerPointerType pCells, - TXmlDataElementWrapper& rXmlDataElementWrapper, - const IndexType EchoLevel) -{ - std::visit([&rCellElement, &rXmlDataElementWrapper, &rWritingIndices, &rNodes, EchoLevel](auto p_container) { - std::unordered_map indices_map; - indices_map.reserve(rNodes.size()); - IndexType vtu_index = 0; - for (const auto& r_node : rNodes) { - indices_map[r_node.Id()] = vtu_index++; - } - - KRATOS_INFO_IF("VtuOutput", EchoLevel > 2) << "------ Collecting Vtk geometry type info...\n"; - auto p_type_data = GetGeometryTypes(rWritingIndices, *p_container, EchoLevel); - - KRATOS_INFO_IF("VtuOutput", EchoLevel > 2) << "------ Ignored " << (p_container->size() - rWritingIndices.size()) << "/" - << p_container->size() << " " << GetEntityName(p_container) << "(s).\n"; - - KRATOS_INFO_IF("VtuOutput", EchoLevel > 2) << "------ Collecting geometry offsets info...\n"; - auto p_offsets = GetOffsets(rWritingIndices, *p_container); - - KRATOS_INFO_IF("VtuOutput", EchoLevel > 2) << "------ Collecting geometry connectivity info...\n"; - rCellElement.AddElement(rXmlDataElementWrapper.Get("connectivity", GetConnectivities(*p_offsets, *p_container, indices_map, rWritingIndices))); - rCellElement.AddElement(rXmlDataElementWrapper.Get("offsets", p_offsets)); - rCellElement.AddElement(rXmlDataElementWrapper.Get("types", GetWritingNDData(rWritingIndices, p_type_data))); - }, pCells); -} - -template -void AddFieldsUsingTensorAdaptorImpl( - XmlElementsArray& rXmlElement, - TContainerPointerType pContainer, - const Variable& rVariable, - TXmlDataElementWrapper& rXmlDataElementWrapper, - const DataCommunicator& rDataCommunicator, - const std::vector& rWritingIndices, - const IndexType EchoLevel, - TArgs&&... rArgs) -{ - KRATOS_TRY - - - using primitive_data_type = typename DataTypeTraits::PrimitiveType; - - if constexpr(std::is_same_v) { - // we only support int variable, and there are no TensorAdaptors to - // collect data from integer variables, we do it manually here. - auto p_nd_data = Kratos::make_shared>(DenseVector(1, pContainer->size())); - const auto& shape = p_nd_data->Shape(); - if constexpr (std::is_same_v) { - ContainerIOUtils::CopyToContiguousArray( - *pContainer, p_nd_data->ViewData(), - shape.data().begin(), shape.data().begin() + 1, - [&rVariable](int& rValue, const Node& rNode) { - rValue = rNode.FastGetSolutionStepValue(rVariable); - }); - } else if constexpr(std::is_same_v) { - ContainerIOUtils::CopyToContiguousArray( - *pContainer, p_nd_data->ViewData(), - shape.data().begin(), shape.data().begin() + 1, - [&rVariable](int& rValue, const auto& rNode) { - rValue = rNode.GetValue(rVariable); - }); - } else { - KRATOS_ERROR << "Unsupported tensor adaptor type."; - } - - // since we only support Variable, which is having a static data shape - // we don't have to do mpi communication to decide the shape on the - // empty ranks. - rXmlElement.AddElement(rXmlDataElementWrapper.Get(rVariable.Name(), GetWritingNDData(rWritingIndices, p_nd_data))); - } else if constexpr(std::is_same_v) { - using data_type_traits = DataTypeTraits; - - if constexpr(data_type_traits::IsDynamic) { - // this is a dynamic type such as Vector or Matrix, so - // we need to do communication to decide the correct size - // because, there may be ranks with zero entities, hence these ranks will not have - // correctly sized dynamic Matrix or Vectors. Vtu needs all the ranks to have the same number - // of components, hence communication is a must in here. - - // construct the correct data_shape - std::vector data_shape(data_type_traits::Dimension, 0); - - if (!pContainer->empty()) { - // if the container is not empty. - TTensorAdaptorType tensor_adaptor(pContainer, &rVariable, rArgs...); - tensor_adaptor.CollectData(); - - const auto& ta_shape = tensor_adaptor.Shape(); - std::copy(ta_shape.begin() + 1, ta_shape.end(), data_shape.begin()); - - // create the xml element in ranks which do have entities. - rXmlElement.AddElement(rXmlDataElementWrapper.Get(rVariable.Name(), GetWritingNDData(rWritingIndices, tensor_adaptor.pGetStorage()))); - } - - // communicate to identify the correct data shape to be written down to ranks which - // do not have any entities. - const auto& max_data_shape = rDataCommunicator.MaxAll(data_shape); - - if (pContainer->empty()) { - // if the container is empty, now create an empty NDData with correct data shape. - DenseVector nd_shape(max_data_shape.size() + 1); - std::copy(max_data_shape.begin(), max_data_shape.end(), nd_shape.begin() + 1); - nd_shape[0] = pContainer->size(); - auto p_nd_data = Kratos::make_shared(nd_shape); - - // create the xml element in ranks which do not have any entities. - rXmlElement.AddElement(rXmlDataElementWrapper.Get(rVariable.Name(), p_nd_data)); - } - } else { - // this is a static type such as double, array_1d, ... - // So no need of mpi communication - TTensorAdaptorType tensor_adaptor(pContainer, &rVariable, rArgs...); - tensor_adaptor.CollectData(); - rXmlElement.AddElement(rXmlDataElementWrapper.Get(rVariable.Name(), GetWritingNDData(rWritingIndices, tensor_adaptor.pGetStorage()))); - } - } else { - KRATOS_ERROR << "Unsupported variable type."; - } - - KRATOS_CATCH(""); -} - -template -void AddFieldsUsingTensorAdaptor( - XmlElementsArray& rXmlElement, - TContainerPointerType pContainer, - const TMapType& rMap, - TXmlDataElementWrapper& rXmlDataElementWrapper, - const DataCommunicator& rDataCommunicator, - const std::vector& rWritingIndices, - const IndexType EchoLevel, - TArgs&&... rArgs) -{ - KRATOS_TRY - - for (const auto& r_pair : rMap) { - using data_type = BareType; - - KRATOS_INFO_IF("VtuOutput", EchoLevel > 2) << "------ Collecting " << r_pair.first << " data...\n"; - - if constexpr(std::is_same_v) { - if (r_pair.first == "KRATOS_ID") { - // this is specific to write KRATOS_IDS. - auto p_nd_data = Kratos::make_shared>(DenseVector(1, rWritingIndices.size())); - auto span = p_nd_data->ViewData(); - IndexPartition(rWritingIndices.size()).for_each([&pContainer, &span, &rWritingIndices](const auto Index) { - span[Index] = (pContainer->begin() + rWritingIndices[Index])->Id(); - }); - rXmlElement.AddElement(rXmlDataElementWrapper.Get(r_pair.first, p_nd_data)); - } else { - // the map is of type flags - // here we don't need to do any communication because Flags are always having a static data shape. - TTensorAdaptorType tensor_adaptor(pContainer, *r_pair.second, rArgs...); - tensor_adaptor.CollectData(); - rXmlElement.AddElement(rXmlDataElementWrapper.Get(r_pair.first, GetWritingNDData(rWritingIndices, tensor_adaptor.pGetStorage()))); - } - } else { - std::visit([&](const auto p_variable) { - AddFieldsUsingTensorAdaptorImpl( - rXmlElement, pContainer, *p_variable, rXmlDataElementWrapper, - rDataCommunicator, rWritingIndices, EchoLevel, rArgs...); - }, r_pair.second); - } - } - - KRATOS_CATCH(""); -} - -template -void AddFields( - XmlElementsArray& rXmlElement, - const std::map& rMap, - TXmlDataElementWrapper& rXmlDataElementWrapper, - const std::vector& rWritingIndices, - const DataCommunicator& rDataCommunicator, - const IndexType EchoLevel) -{ - for (const auto& r_pair : rMap) { - KRATOS_INFO_IF("VtuOutput", EchoLevel > 2) << "------ Collecting " << r_pair.first << " data...\n"; - - std::visit([&rXmlElement, &r_pair, &rXmlDataElementWrapper, &rWritingIndices, &rDataCommunicator](auto pTensorAdaptor) { - // here we need to make sure all the tensor adaptors from every rank has the same data shape, even - // from the ranks which do not have any entities. Therefore following check is done with mpi communication - - // all the ranks should have the same number of dimensions, because number of dimensions should not depend - // on whether the rank is empty or not. - const auto& ta_shape = pTensorAdaptor->Shape(); - const auto max_number_of_dimensions = rDataCommunicator.MaxAll(static_cast(ta_shape.size())); - - KRATOS_ERROR_IF_NOT(max_number_of_dimensions == ta_shape.size()) - << "The number of dimensions represented by \"" << r_pair.first << "\" tensor adaptor is different in different ranks [ max number of dimensions from all ranks = " - << max_number_of_dimensions << ", tensor adaptor = " << *pTensorAdaptor << " ].\n"; - - // since all ranks have same number of dimensions, now we can check if the tensor adaptors have the correct sizes. - // in here we check the followings - // - each rank which does not have emtpy containers (ta_shape[0] != 0) should have same number of components in the data shape. - // - ranks which do have empty containers (ta_shape[0] == 0) should have either same number of components as in the ranks which have non empty - // containers or 0. - - std::vector communicated_shape(ta_shape.begin(), ta_shape.end()); - auto all_ta_shapes = rDataCommunicator.AllGatherv(communicated_shape); - - // find a data shape from some rank which has non-empty container - DenseVector ref_ta_shape(max_number_of_dimensions, 0); - for (const auto& rank_shape : all_ta_shapes) { - if (rank_shape[0] != 0) { - std::copy(rank_shape.begin() + 1, rank_shape.end(), ref_ta_shape.begin() + 1); - break; - } - } - - for (IndexType i_rank = 0; i_rank < all_ta_shapes.size(); ++i_rank) { - auto& rank_shape = all_ta_shapes[i_rank]; - - // modify the rank shape if it is coming from a rank having an empty container. - if (rank_shape[0] == 0) { - // this is a rank with an empty container. - for (IndexType i_dim = 1; i_dim < ref_ta_shape.size(); ++i_dim) { - // modify only if the number of components in the higher dimensions are zero. - if (rank_shape[i_dim] == 0) { - rank_shape[i_dim] = ref_ta_shape[i_dim]; - } - } - } - - // now we check in all ranks whether the data shape is equal - for (IndexType i_dim = 1; i_dim < ref_ta_shape.size(); ++i_dim) { - KRATOS_ERROR_IF_NOT(rank_shape[i_dim] == ref_ta_shape[i_dim]) - << "All ranks should have same number of components in the shape dimensions except for the first dimension. If the rank is empty," - << " then that rank should have zeros for all shape dimensions or correct number of components in the dimensions as in the ranks with" - << " non-empty containers [ mismatching shape rank = " << i_rank << ", mismatching tensor adaptor shape = " << rank_shape - << ", ref tensor adaptor shape from other ranks = " << ref_ta_shape << ", tensor adaptor name = " << r_pair.first - << ", tensor adaptor = " << *pTensorAdaptor << " ].\n"; - } - } - - if (ta_shape[0] == 0) { - // get the storage type of the tensor adaptor. This may be NDData, NDData, ... - using TDataType = typename BareType::Storage; - // this is a rank with an empty container. - rXmlElement.AddElement(rXmlDataElementWrapper.Get(r_pair.first, Kratos::make_shared(ref_ta_shape))); - } else { - // this is a rank with non-empty container. - rXmlElement.AddElement(rXmlDataElementWrapper.Get(r_pair.first, GetWritingNDData(rWritingIndices, pTensorAdaptor->pGetStorage()))); - } - - }, r_pair.second); - } -} - -template -ModelPart::NodesContainerType::Pointer GetNodesContainer(TEntityContainerType& rContainer) -{ - std::vector temp_nodes; - temp_nodes.reserve(rContainer.size() * 20); - for (auto& r_entity : rContainer) { - auto& r_geometry = r_entity.GetGeometry(); - for (auto p_itr = r_geometry.ptr_begin(); p_itr != r_geometry.ptr_end(); ++p_itr) { - temp_nodes.push_back(*p_itr); - } - } - - auto p_nodes_container = Kratos::make_shared(); - p_nodes_container->insert(temp_nodes.begin(), temp_nodes.end()); - return p_nodes_container; -} - -void AddUnstructuredGridData( - std::vector& rOutput, - ModelPart& rModelPart, - const IndexType EchoLevel, - const bool UseSubModelParts) -{ - const std::vector entity_availability{rModelPart.NumberOfNodes() > 0, rModelPart.NumberOfConditions() > 0, rModelPart.NumberOfElements() > 0}; - const auto& max_entity_availability = rModelPart.GetRootModelPart().GetCommunicator().GetDataCommunicator().MaxAll(entity_availability); - const bool has_nodes = max_entity_availability[0]; - const bool has_conditions = max_entity_availability[1]; - const bool has_elements = max_entity_availability[2]; - - if (has_elements) { - // Model part has elements. Hence add a separate output - // for elements. - - // now check if it has proper nodes - if (has_nodes) { - KRATOS_INFO_IF("VtuOutput", EchoLevel > 0) - << "Configuring output for \"" << rModelPart.FullName() << "\" elements with existing nodes container.\n"; - VtuOutput::UnstructuredGridData model_part_data{true, &rModelPart, rModelPart.pNodes(), rModelPart.pElements()}; - rOutput.push_back(model_part_data); - } else { - // create the nodes container. - KRATOS_INFO_IF("VtuOutput", EchoLevel > 0) - << "Configuring output for \"" << rModelPart.FullName() << "\" elements with new nodes container.\n"; - auto p_nodes = GetNodesContainer(rModelPart.Elements()); - VtuOutput::UnstructuredGridData model_part_data{false, &rModelPart, p_nodes, rModelPart.pElements()}; - rOutput.push_back(model_part_data); - } - } - - if (has_conditions) { - // Model part has conditions. Hence add a separate output - // for conditions. - - if (!has_elements && has_nodes) { - KRATOS_INFO_IF("VtuOutput", EchoLevel > 0) - << "Configuring output for \"" << rModelPart.FullName() << "\" conditions with existing nodes container.\n"; - VtuOutput::UnstructuredGridData model_part_data{true, &rModelPart, rModelPart.pNodes(), rModelPart.pConditions()}; - rOutput.push_back(model_part_data); - } else { - // either this model part also contains elements, or it does not - // contain nodes. In either case, the nodes list given by the rModelPart - // does not reflect the actual nodes used by the conditions. - // In order to avoid writing nodes, which are not used by the conditions, - // this will use a new nodes list. - - KRATOS_INFO_IF("VtuOutput", EchoLevel > 0) - << "Configuring output for \"" << rModelPart.FullName() << "\" conditions with new nodes container.\n"; - - auto p_nodes = GetNodesContainer(rModelPart.Conditions()); - VtuOutput::UnstructuredGridData model_part_data{false, &rModelPart, p_nodes, rModelPart.pConditions()}; - rOutput.push_back(model_part_data); - } - } - - if (!has_elements && !has_conditions) { - KRATOS_INFO_IF("VtuOutput", EchoLevel > 0) - << "Configuring output for \"" << rModelPart.FullName() << "\" nodes.\n"; - // Model part does not have either conditions or elements. - // Hence, only adding the nodes. - VtuOutput::UnstructuredGridData model_part_data{true, &rModelPart, rModelPart.pNodes(), std::nullopt}; - rOutput.push_back(model_part_data); - } - - if (UseSubModelParts) { - // now recursively add all the sub model part data. - for (auto& r_sub_model_part : rModelPart.SubModelParts()) { - AddUnstructuredGridData(rOutput, r_sub_model_part, EchoLevel, UseSubModelParts); - } - } -} - -template -const typename VtuOutput::DataList::value_type& GetContainerMap( - const VtuOutput::DataList& rList, - TCellPointerType pCellPointer) -{ - return std::visit([&rList](auto pContainer) -> const typename VtuOutput::DataList::value_type& { - using container_type = BareType; - if constexpr(std::is_same_v) { - return rList[static_cast(Globals::DataLocation::Condition)]; - } else if constexpr(std::is_same_v) { - return rList[static_cast(Globals::DataLocation::Element)]; - } else { - KRATOS_ERROR << "Unsupported container type."; - return rList[static_cast(Globals::DataLocation::Element)]; - } - }, pCellPointer); -} - -std::string WritePartitionedUnstructuredGridData( - XmlElementsArray& rPointDataElement, - XmlElementsArray& rCellDataElement, - const std::string& rOutputVtuFileName, - const DataCommunicator& rDataCommunicator) -{ - const int writing_rank = 0; - - // remove the rank from the rOutputVtuFileName. - const auto& r_base_name = rOutputVtuFileName.substr(0, rOutputVtuFileName.rfind("_")); - - const auto& p_vtu_file_name = r_base_name + ".pvtu"; - - if (rDataCommunicator.Rank() == writing_rank) { - // create the pvtu file - XmlElementsArray p_vtu_file_element("VTKFile"); - p_vtu_file_element.AddAttribute("type", "PUnstructuredGrid"); - p_vtu_file_element.AddAttribute("version", "0.1"); - p_vtu_file_element.AddAttribute("byte_order", GetEndianness()); - - // create the unstructured grid - auto p_unstructured_grid_element = Kratos::make_shared("PUnstructuredGrid"); - p_unstructured_grid_element->AddAttribute("GhostLevel", "0"); - p_vtu_file_element.AddElement(p_unstructured_grid_element); - - // ppoints_element - auto p_points_element = Kratos::make_shared("PPoints"); - p_unstructured_grid_element->AddElement(p_points_element); - - // position element - auto p_position_element = Kratos::make_shared("PDataArray"); - p_position_element->AddAttribute("type", "Float64"); - p_position_element->AddAttribute("Name", "Position"); - p_position_element->AddAttribute("NumberOfComponents", "3"); - p_points_element->AddElement(p_position_element); - - // pcells element - auto p_cells_element = Kratos::make_shared("PCells"); - p_unstructured_grid_element->AddElement(p_cells_element); - - // connectivity element - auto p_connectivity_element = Kratos::make_shared("PDataArray"); - p_connectivity_element->AddAttribute("type", "Int32"); - p_connectivity_element->AddAttribute("Name", "connectivity"); - p_connectivity_element->AddAttribute("NumberOfComponents", "1"); - p_cells_element->AddElement(p_connectivity_element); - - // offsets element - auto p_offsets_element = Kratos::make_shared("PDataArray"); - p_offsets_element->AddAttribute("type", "Int32"); - p_offsets_element->AddAttribute("Name", "offsets"); - p_offsets_element->AddAttribute("NumberOfComponents", "1"); - p_cells_element->AddElement(p_offsets_element); - - // types element - auto p_types_element = Kratos::make_shared("PDataArray"); - p_types_element->AddAttribute("type", "UInt8"); - p_types_element->AddAttribute("Name", "types"); - p_types_element->AddAttribute("NumberOfComponents", "1"); - p_cells_element->AddElement(p_types_element); - - // ppoint data element - auto p_point_data_element = Kratos::make_shared("PPointData"); - p_unstructured_grid_element->AddElement(p_point_data_element); - - // now add the point data fields - for (const auto& p_element : rPointDataElement.GetElements()) { - auto p_current_element = Kratos::make_shared("PDataArray"); - CopyAttributes(*p_element, *p_current_element); - p_point_data_element->AddElement(p_current_element); - } - - // pcell data element - auto p_cell_data_element = Kratos::make_shared("PCellData"); - p_unstructured_grid_element->AddElement(p_cell_data_element); - - // now add the cell data fields - for (const auto& p_element : rCellDataElement.GetElements()) { - auto p_current_element = Kratos::make_shared("PDataArray"); - CopyAttributes(*p_element, *p_current_element); - p_cell_data_element->AddElement(p_current_element); - } - - // now add the piece elements - for (int i_rank = 0; i_rank < rDataCommunicator.Size(); ++i_rank) { - const auto& r_file_name = r_base_name + "_" + std::to_string(i_rank) + ".vtu"; - auto piece = Kratos::make_shared("Piece"); - // since we are writing to the same folder the pvtu files - piece->AddAttribute( - "Source", std::filesystem::relative( - std::filesystem::absolute(r_file_name), - std::filesystem::absolute(p_vtu_file_name).parent_path()) - .generic_string()); - p_unstructured_grid_element->AddElement(piece); - } - - // writing to file - std::ofstream output_file; - output_file.open(p_vtu_file_name, std::ios::out | std::ios::trunc); - output_file << "\n"; - p_vtu_file_element.Write(output_file); - - } - - return p_vtu_file_name; -} - -template -void PrintDataLocationData( - std::ostream& rOStream, - const std::string& rMapType, - const VtuOutput::DataList& rList) -{ - rOStream << "List of " << rMapType << "s:"; - for (IndexType i = 0; i < rList.size(); ++i) { - switch (i) { - case static_cast(Globals::DataLocation::NodeHistorical): - rOStream << "\n\tNode historical " << rMapType << "s:"; - break; - case static_cast(Globals::DataLocation::NodeNonHistorical): - rOStream << "\n\tNode " << rMapType << "s:"; - break; - case static_cast(Globals::DataLocation::Condition): - rOStream << "\n\tCondition " << rMapType << "s:"; - break; - case static_cast(Globals::DataLocation::Element): - rOStream << "\n\tElement " << rMapType << "s:"; - break; - default: - break; - } - - for ([[maybe_unused]]const auto& [name, variable] : rList[i]) { - rOStream << "\n\t\t" << name; - } - } -} - -template -std::pair::iterator> FindUnstructuredGridData( - const TContainerType& rContainer, - std::vector& rUnstructuredGridDataList) -{ - for (auto itr = rUnstructuredGridDataList.begin(); itr != rUnstructuredGridDataList.end(); ++itr) { - auto p_model_part = itr->mpModelPart; - if constexpr(std::is_same_v) { - if (itr->UsePointsForDataFieldOutput) { - if ( - &rContainer == &p_model_part->Nodes() || - (!p_model_part->IsDistributed() && &rContainer == &p_model_part->GetCommunicator().LocalMesh().Nodes()) - ) { - return std::make_pair(Globals::DataLocation::NodeNonHistorical, itr); - } - } - } else if constexpr(std::is_same_v) { - // since Kratos is doing partitioning based on elements, and there are no conditions - // on the ghost meshes. so normal mesh and the local mesh should be having identical entities. - if (itr->mpCells.has_value() && - std::holds_alternative(itr->mpCells.value()) && - ( - &rContainer == &*std::get(itr->mpCells.value()) || - &rContainer == &p_model_part->GetCommunicator().LocalMesh().Conditions() - ) - ) { - return std::make_pair(Globals::DataLocation::Condition, itr); - } - } else if constexpr(std::is_same_v) { - // since Kratos is doing partitioning based on elements, and there are no elements - // on the ghost meshes. so normal mesh and the local mesh should be having identical entities. - if (itr->mpCells.has_value() && - std::holds_alternative(itr->mpCells.value()) && - ( - &rContainer == &*std::get(itr->mpCells.value()) || - &rContainer == &p_model_part->GetCommunicator().LocalMesh().Elements() - ) - ) { - return std::make_pair(Globals::DataLocation::Element, itr); - } - } else { - KRATOS_ERROR << "Unsupported container type."; - } - } - - return std::make_pair(Globals::DataLocation::ModelPart, rUnstructuredGridDataList.end()); -} - -} // namespace - -VtuOutput::VtuOutput( - ModelPart& rModelPart, - const Globals::Configuration Configuration, - const WriterFormat OutputFormat, - const IndexType Precision, - const bool OutputSubModelParts, - const bool WriteIds, - const IndexType EchoLevel) - : mIsPVDFileHeaderWritten(false), - mrModelPart(rModelPart), - mConfiguration(Configuration), - mEchoLevel(EchoLevel), - mOutputFormat(OutputFormat), - mPrecision(Precision) -{ - AddUnstructuredGridData(mUnstructuredGridDataList, rModelPart, mEchoLevel, OutputSubModelParts); - - // sort the order of output to be consistent between different compilers - std::sort(mUnstructuredGridDataList.begin(), mUnstructuredGridDataList.end(), - [](const auto& rV1, const auto& rV2) { - return rV1.mpModelPart->FullName() < rV2.mpModelPart->FullName(); - }); - - if (WriteIds) { - // Adds a dummy place holder called "KRATOS_ID" to every container type - // so the user is prohibited from adding any tensor adaptors - // with the name KRATOS_ID in future. This will be treated - // separately, hence the use of nullptr. - mFlags[static_cast(Globals::DataLocation::NodeNonHistorical)]["KRATOS_ID"] = nullptr; - mFlags[static_cast(Globals::DataLocation::Condition)]["KRATOS_ID"] = nullptr; - mFlags[static_cast(Globals::DataLocation::Element)]["KRATOS_ID"] = nullptr; - } -} - -const ModelPart& VtuOutput::GetModelPart() const -{ - return mrModelPart; -} - -std::vector VtuOutput::GetOutputContainerList() const -{ - std::vector result; - for (const auto& r_unstructured_grid : mUnstructuredGridDataList) { - if (r_unstructured_grid.UsePointsForDataFieldOutput) { - result.push_back(r_unstructured_grid.mpPoints); - - if (!r_unstructured_grid.mpModelPart->GetRootModelPart().IsDistributed()) { - // since local mesh and the mesh are the same in the case of non-distributed - // run. - result.push_back(r_unstructured_grid.mpModelPart->GetCommunicator().LocalMesh().pNodes()); - } - } - - if (r_unstructured_grid.mpCells.has_value()) { - std::visit([&result, &r_unstructured_grid](auto p_cells) { - result.push_back(p_cells); - - // since local mesh and the mesh are the same. - using container_type = BareType; - if constexpr(std::is_same_v) { - result.push_back(r_unstructured_grid.mpModelPart->GetCommunicator().LocalMesh().pConditions()); - } else if constexpr(std::is_same_v) { - result.push_back(r_unstructured_grid.mpModelPart->GetCommunicator().LocalMesh().pElements()); - } - }, r_unstructured_grid.mpCells.value()); - } - } - return result; -} - -void VtuOutput::AddFlag( - const std::string& rFlagName, - const Flags& rFlagVariable, - const Globals::DataLocation& DataLocation) -{ - KRATOS_TRY - - KRATOS_ERROR_IF(mIsPVDFileHeaderWritten) - << "Flags can be added only before the first call to the PrintOutput [ flag name = " - << rFlagName << " ].\n"; - - switch (DataLocation) { - case Globals::DataLocation::NodeNonHistorical: - // user is trying to add a flag to nodes. now we are checking - // whether there are variables with the same name in the variables - // from the nodal historical. - // note: there is no break here. - CheckDataArrayName(rFlagName, Globals::DataLocation::NodeHistorical, mFlags); - CheckDataArrayName(rFlagName, Globals::DataLocation::NodeHistorical, mVariables); - case Globals::DataLocation::Condition: - case Globals::DataLocation::Element: - // The following code block will be executed for Globals::DataLocation::NodeHistorical, Globals::DataLocation::Condition, and Globals::DataLocation::Element. - - // user is trying to add a flag variable to nodes, conditions or elements. - // here we check if the given flag name is there in the existing flags for user specified data location, - // and also in the variables. - CheckDataArrayName(rFlagName, DataLocation, mFlags); - CheckDataArrayName(rFlagName, DataLocation, mVariables); - - // since specified flags are used to output in every unstructured grid. We check here whether - // any of the tensor adaptors in the given data location contains the same name as rFlagName. - CheckDataArrayName(rFlagName, DataLocation, mUnstructuredGridDataList); - - // If there are no conflicts, we add the flag variable. - mFlags[static_cast(DataLocation)][rFlagName] = &rFlagVariable; - break; - default: - KRATOS_ERROR << "Flags can be only added to NodeNonHistorical, Condition, and Element data locations."; - break; - } - - KRATOS_CATCH(""); -} - -template -void VtuOutput::AddVariable( - const Variable& rVariable, - const Globals::DataLocation& DataLocation) -{ - KRATOS_TRY - - KRATOS_ERROR_IF(mIsPVDFileHeaderWritten) - << "Variables can be added only before the first call to the PrintOutput [ variable name = " - << rVariable.Name() << " ].\n"; - - switch (DataLocation) { - case Globals::DataLocation::NodeHistorical: - // Now the user is adding a nodal historical variable. So, this checks whether - // the a variable with the same name exists in the nodal non-historical variables map. - // note: there is no break in here. - CheckDataArrayName(rVariable.Name(), Globals::DataLocation::NodeNonHistorical, mFlags); - CheckDataArrayName(rVariable.Name(), Globals::DataLocation::NodeNonHistorical, mVariables); - case Globals::DataLocation::NodeNonHistorical: - // Now the user is adding a nodal non-historical variable. So this checks whether - // a variable with the same name exists in the nodal historical variables map. - // not: there is no break in here. - CheckDataArrayName(rVariable.Name(), Globals::DataLocation::NodeHistorical, mFlags); - CheckDataArrayName(rVariable.Name(), Globals::DataLocation::NodeHistorical, mVariables); - case Globals::DataLocation::Condition: - case Globals::DataLocation::Element: - // The following code block will be executed for Globals::DataLocation::NodeHistorical, Globals::DataLocation::NodeNonHistorical, Globals::DataLocation::Condition, and Globals::DataLocation::Element. - - // Now the user is trying to add a nodal-historical, nodal-non-historical, element or condition variable. - // so now we check whether another variable with the same name exists - // in the user specified container in flags and variables maps. - CheckDataArrayName(rVariable.Name(), DataLocation, mFlags); - CheckDataArrayName(rVariable.Name(), DataLocation, mVariables); - - // this checks whether there is already a tensor adaptor added with a name equal to the variable name - // in any of the unstructured grids. Since these variables will be used to output data in all the unstructured grids, - // non-of them should have any tensor adaptors with this name. - CheckDataArrayName(rVariable.Name(), DataLocation, mUnstructuredGridDataList); // checks in the tensor adaptors list - - // if there are no conflicts, adding the variable. - mVariables[static_cast(DataLocation)][rVariable.Name()] = &rVariable; - break; - default: - KRATOS_ERROR << "Variables can be only added to NodeHistorical, NodeNonHistorical, Condition, and Element data locations."; - break; - } - - KRATOS_CATCH(""); -} - -template -void VtuOutput::AddIntegrationPointVariable( - const Variable& rVariable, - const Globals::DataLocation& DataLocation) -{ - KRATOS_TRY - - KRATOS_ERROR_IF(mIsPVDFileHeaderWritten) - << "Integration point variables can be added only before the first call to the PrintOutput [ integration point variable name = " - << rVariable.Name() << " ].\n"; - - switch (DataLocation) { - case Globals::DataLocation::Condition: - case Globals::DataLocation::Element: - // The following code block will be executed for Globals::DataLocation::Condition and Globals::DataLocation::Element. - - // checks if the integration point variable name already exists on the - // list of integration point variables. - CheckDataArrayName(rVariable.Name(), DataLocation, mIntegrationPointVariables); - - // If no conflicts in the naming is found, then put integration point variable for the output. - mIntegrationPointVariables[static_cast(DataLocation)][rVariable.Name()] = &rVariable; - break; - default: - KRATOS_ERROR << "Integration point variables can be only added to Condition, and Element data locations."; - break; - } - - KRATOS_CATCH(""); -} - -template -void VtuOutput::AddTensorAdaptor( - const std::string& rTensorAdaptorName, - TTensorAdaptorPointerType pTensorAdaptor) -{ - KRATOS_TRY - - KRATOS_ERROR_IF(mIsPVDFileHeaderWritten) - << "TensorAdaptors can be added only before the first call to the PrintOutput [ tensor adaptor name = " - << rTensorAdaptorName << " ].\n"; - - // a visitor for NodesContainer::Pointer, ConditionsContainer::Pointer, ElementsContainerPointer - // of the given pTensorAdaptor - std::visit([this, &rTensorAdaptorName, &pTensorAdaptor](auto pContainer){ - // finds the unstructured grid for which the given tensor adaptor's pContainer refers to. - // mesh_type is of Kratos::Globals::DataLocation enum - // itr points to the unstructured grid which is referring to the given pContainer. - // if not found, mesh_type is returned with Kratos::Globals::DataLocation::ModelPart - // enum value, which will throw an error. - [[maybe_unused]] auto [mesh_type, itr] = FindUnstructuredGridData(*pContainer, this->mUnstructuredGridDataList); - - switch (mesh_type) { - case Globals::DataLocation::Condition: - case Globals::DataLocation::Element: { - // The following code block will be executed for Globals::DataLocation::Condition and Globals::DataLocation::Element. - - // here we have to check if the specified tensor adaptor name is there in the found unstructured grid - // referred by the itr. - - // checks in the condition or element maps of flags and variables whether the rTensorAdaptorName already - // exists. - CheckDataArrayName(rTensorAdaptorName, mesh_type, mFlags); // checks in the current data location of mFlags map - CheckDataArrayName(rTensorAdaptorName, mesh_type, mVariables); // checks in the current data location of mVariables map - - // checks in either Condition or Element map of tensor adaptors whether the given rTensorAdaptorName - // exists - CheckDataArrayName(rTensorAdaptorName, mesh_type, *itr); - - // If no conflicts in the naming is found, then put the tensor adaptor for output. - itr->mMapOfCellTensorAdaptors[rTensorAdaptorName] = pTensorAdaptor; - break; - } - case Globals::DataLocation::NodeNonHistorical: { - // checks if the given rTensorAdaptorName is already there in the nodal non-historical - // variables list, nodal-non-historical variables list and flags list. - CheckDataArrayName(rTensorAdaptorName, Globals::DataLocation::NodeNonHistorical, mFlags); - CheckDataArrayName(rTensorAdaptorName, Globals::DataLocation::NodeNonHistorical, mVariables); - CheckDataArrayName(rTensorAdaptorName, Globals::DataLocation::NodeHistorical, mFlags); - CheckDataArrayName(rTensorAdaptorName, Globals::DataLocation::NodeHistorical, mVariables); - - // checks if the given rTensorAdaptorName is already there in the list of nodal tensor adaptors - // of the unstructured grid referred by itr. - CheckDataArrayName(rTensorAdaptorName, Globals::DataLocation::NodeNonHistorical, *itr); - - // If no conflicts in the naming is found, then put the tensor adaptor for output. - itr->mMapOfPointTensorAdaptors[rTensorAdaptorName] = pTensorAdaptor; - break; - } - default: - KRATOS_ERROR - << "The container in the TensorAdaptor is not referring to any of the containers " - << "written by this Vtu output [ tensor adaptor name = " << rTensorAdaptorName - << ", tensor_adaptor = " << *pTensorAdaptor << " ]\n" - << *this; - break; - } - }, pTensorAdaptor->GetContainer()); - - KRATOS_CATCH(""); -} - -template -void VtuOutput::ReplaceTensorAdaptor( - const std::string& rTensorAdaptorName, - TTensorAdaptorPointerType pTensorAdaptor) -{ - KRATOS_TRY - - // a visitor for NodesContainer::Pointer, ConditionsContainer::Pointer, ElementsContainerPointer - // of the given pTensorAdaptor - std::visit([this, &rTensorAdaptorName, &pTensorAdaptor](auto pContainer){ - // finds the unstructured grid for which the given tensor adaptor's pContainer refers to. - // mesh_type is of Kratos::Globals::DataLocation enum - // itr points to the unstructured grid which is referring to the given pContainer. - // if not found, mesh_type is returned with Kratos::Globals::DataLocation::ModelPart - // enum value, which will throw an error. - [[maybe_unused]] auto [mesh_type, itr] = FindUnstructuredGridData(*pContainer, this->mUnstructuredGridDataList); - - switch (mesh_type) { - case Globals::DataLocation::Condition: - case Globals::DataLocation::Element: { - // The following code block will be executed for Globals::DataLocation::Condition and Globals::DataLocation::Element. - auto data_field_itr = itr->mMapOfCellTensorAdaptors.find(rTensorAdaptorName); - - KRATOS_ERROR_IF(data_field_itr == itr->mMapOfCellTensorAdaptors.end()) - << "TensorAdaptor name = \"" - << rTensorAdaptorName << "\" not found in the existing data fields. It is only allowed to update existing data fields. VtuOutput: \n" - << *this; - - data_field_itr->second = pTensorAdaptor; - break; - } - case Globals::DataLocation::NodeNonHistorical: { - auto data_field_itr = itr->mMapOfPointTensorAdaptors.find(rTensorAdaptorName); - - KRATOS_ERROR_IF(data_field_itr == itr->mMapOfPointTensorAdaptors.end()) - << "TensorAdaptor name = \"" - << rTensorAdaptorName << "\" not found in the existing data fields. It is only allowed to update existing data fields. VtuOutput: \n" - << *this; - - data_field_itr->second = pTensorAdaptor; - break; - } - default: - KRATOS_ERROR - << "The container in the TensorAdaptor is not referring to any of the containers " - << "written by this Vtu output [ tensor adaptor name = " << rTensorAdaptorName - << ", tensor_adaptor = " << *pTensorAdaptor << " ]\n" - << *this; - break; - } - }, pTensorAdaptor->GetContainer()); - - KRATOS_CATCH(""); -} - -template -void VtuOutput::EmplaceTensorAdaptor( - const std::string& rTensorAdaptorName, - TTensorAdaptorPointerType pTensorAdaptor) -{ - if (!mIsPVDFileHeaderWritten) { - AddTensorAdaptor(rTensorAdaptorName, pTensorAdaptor); - } else { - ReplaceTensorAdaptor(rTensorAdaptorName, pTensorAdaptor); - } -} - -template -std::pair VtuOutput::WriteUnstructuredGridData( - TXmlElementDataWrapperCreateFunctor&& rElementDataWrapperCreateFunctor, - TXmlElementDataWrapperAppendFunctor&& rElementDataWrapperAppendFunctor, - UnstructuredGridData& rUnstructuredGridData, - const std::string& rOutputFileNamePrefix, - const IndexType Step) const -{ - const auto& r_data_communicator = mrModelPart.GetCommunicator().GetDataCommunicator(); - auto p_nodes = rUnstructuredGridData.mpPoints; - - // create the vtk file - XmlElementsArray vtk_file_element("VTKFile"); - vtk_file_element.AddAttribute("type", "UnstructuredGrid"); - vtk_file_element.AddAttribute("version", "0.1"); - vtk_file_element.AddAttribute("byte_order", GetEndianness()); - - // create the unstructured grid - auto unstructured_grid_element = Kratos::make_shared("UnstructuredGrid"); - vtk_file_element.AddElement(unstructured_grid_element); - - auto p_xml_data_element_wrapper = rElementDataWrapperCreateFunctor(); - rElementDataWrapperAppendFunctor(vtk_file_element, p_xml_data_element_wrapper); - - // create the piece element - auto piece_element = Kratos::make_shared("Piece"); - // adding number of points - piece_element->AddAttribute("NumberOfPoints", std::to_string(p_nodes->size())); - unstructured_grid_element->AddElement(piece_element); - - // create the position element - KRATOS_INFO_IF("VtuOutput", mEchoLevel > 2) << "--- Collecting nodal " << (mConfiguration == Globals::Configuration::Initial ? "initial" : "current") << " position data...\n"; - NodePositionTensorAdaptor node_position_tensor_adaptor(p_nodes, mConfiguration); - node_position_tensor_adaptor.CollectData(); - - // create the points element - auto points_element = Kratos::make_shared("Points"); - points_element->AddElement(p_xml_data_element_wrapper->Get("Position", node_position_tensor_adaptor.pGetStorage())); - piece_element->AddElement(points_element); - - // create the cells element - auto cells_element = Kratos::make_shared("Cells"); - std::vector writing_indices; - if (rUnstructuredGridData.mpCells.has_value()) { - KRATOS_INFO_IF("VtuOutput", mEchoLevel > 2) << "--- Collecting " << GetEntityName(rUnstructuredGridData.mpCells) << " connectivity data...\n"; - AddConnectivityData(*cells_element, writing_indices, *rUnstructuredGridData.mpPoints, rUnstructuredGridData.mpCells.value(), *p_xml_data_element_wrapper, mEchoLevel); - } - piece_element->AddAttribute("NumberOfCells", std::to_string(writing_indices.size())); - piece_element->AddElement(cells_element); - - // create the point data - auto point_data_element = Kratos::make_shared("PointData"); - piece_element->AddElement(point_data_element); - - if (rUnstructuredGridData.UsePointsForDataFieldOutput) { - KRATOS_INFO_IF("VtuOutput", mEchoLevel > 2) << "--- Collecting nodal data fields...\n"; - // generate and add point field data - std::vector all_indices(p_nodes->size()); - std::iota(all_indices.begin(), all_indices.end(), 0); - AddFieldsUsingTensorAdaptor(*point_data_element, p_nodes, mFlags[static_cast(Globals::DataLocation::NodeNonHistorical)], *p_xml_data_element_wrapper, r_data_communicator, all_indices, mEchoLevel); - AddFieldsUsingTensorAdaptor(*point_data_element, p_nodes, mVariables[static_cast(Globals::DataLocation::NodeNonHistorical)], *p_xml_data_element_wrapper, r_data_communicator, all_indices, mEchoLevel); - AddFieldsUsingTensorAdaptor(*point_data_element, p_nodes, mVariables[static_cast(Globals::DataLocation::NodeHistorical)], *p_xml_data_element_wrapper, r_data_communicator, all_indices, mEchoLevel, 0); - AddFields(*point_data_element, rUnstructuredGridData.mMapOfPointTensorAdaptors, *p_xml_data_element_wrapper, all_indices, r_data_communicator, mEchoLevel); - } - - // create cell data - auto cell_data_element = Kratos::make_shared("CellData"); - piece_element->AddElement(cell_data_element); - - // generate and add cell field data - if (rUnstructuredGridData.mpCells.has_value()) { - KRATOS_INFO_IF("VtuOutput", mEchoLevel > 2) << "--- Collecting " << GetEntityName(rUnstructuredGridData.mpCells) << " data fields...\n"; - std::visit([this, &rUnstructuredGridData, &cell_data_element, &p_xml_data_element_wrapper, &r_data_communicator, &writing_indices](auto p_container){ - AddFieldsUsingTensorAdaptor(*cell_data_element, p_container, GetContainerMap(this->mVariables, rUnstructuredGridData.mpCells.value()), *p_xml_data_element_wrapper, r_data_communicator, writing_indices, mEchoLevel); - AddFieldsUsingTensorAdaptor(*cell_data_element, p_container, GetContainerMap(this->mFlags, rUnstructuredGridData.mpCells.value()), *p_xml_data_element_wrapper, r_data_communicator, writing_indices, mEchoLevel); - }, rUnstructuredGridData.mpCells.value()); - AddFields(*cell_data_element, rUnstructuredGridData.mMapOfCellTensorAdaptors, *p_xml_data_element_wrapper, writing_indices, r_data_communicator, mEchoLevel); - } - - std::stringstream output_vtu_file_name; - output_vtu_file_name << rOutputFileNamePrefix << "/" << rUnstructuredGridData.mpModelPart->FullName(); - - // identify suffix with the entity type. - const std::string& suffix = "_" + GetEntityName(rUnstructuredGridData.mpCells) + "s"; - - const std::string pvd_data_set_name = rUnstructuredGridData.mpModelPart->FullName() + suffix; - - // append with the step value and rank and extension - output_vtu_file_name << suffix << "_" << Step - << (r_data_communicator.IsDistributed() - ? "_" + std::to_string(r_data_communicator.Rank()) - : "") - << ".vtu"; - - // write the vtu file. - std::ofstream output_file; - output_file.open(output_vtu_file_name.str(), std::ios::out | std::ios::trunc | std::ios::binary); - output_file << "\n"; - vtk_file_element.Write(output_file); - output_file.close(); - - // if it is run on a distributed system, create the pvtu file. - if (r_data_communicator.IsDistributed()) { - return std::make_pair(pvd_data_set_name, - WritePartitionedUnstructuredGridData( - *point_data_element, *cell_data_element, - output_vtu_file_name.str(), r_data_communicator)); - } - - // return the final file name for - return std::make_pair(pvd_data_set_name, output_vtu_file_name.str()); -} - -template -std::pair VtuOutput::WriteIntegrationPointData( - TXmlElementDataWrapperCreateFunctor&& rElementDataWrapperCreateFunctor, - TXmlElementDataWrapperAppendFunctor&& rElementDataWrapperAppendFunctor, - UnstructuredGridData& rUnstructuredGridData, - const std::string& rOutputFileNamePrefix, - const IndexType Step) const -{ - if (!rUnstructuredGridData.mpCells.has_value()) { - // nothing to do here. - return std::make_pair("", ""); - } - - const auto& integration_point_vars = GetContainerMap( - mIntegrationPointVariables, rUnstructuredGridData.mpCells.value()); - - if (integration_point_vars.empty()) { - // nothing to do here. - return std::make_pair("", ""); - } - - // create the vtk file - XmlElementsArray vtk_file_element("VTKFile"); - vtk_file_element.AddAttribute("type", "UnstructuredGrid"); - vtk_file_element.AddAttribute("version", "0.1"); - vtk_file_element.AddAttribute("byte_order", GetEndianness()); - - // create the unstructured grid - auto unstructured_grid_element = Kratos::make_shared("UnstructuredGrid"); - vtk_file_element.AddElement(unstructured_grid_element); - - auto p_xml_data_element_wrapper = rElementDataWrapperCreateFunctor(); - rElementDataWrapperAppendFunctor(vtk_file_element, p_xml_data_element_wrapper); - - DenseVector offsets; - - const auto total_gauss_points = std::visit([&offsets](auto p_container) { - // resize the offsets - offsets.resize(p_container->size(), false); - - IndexType total_number_of_gauss_points = 0; - - // now compute the offsets for each entity. This allows - // having different number of gps in different entities. - // which is the case if we have a model part with mixed type - // of elements. - for (IndexType i = 0; i < p_container->size(); ++i) { - const auto& r_entity = *(p_container->begin() + i); - const auto number_of_gps = r_entity.GetGeometry().IntegrationPointsNumber(r_entity.GetIntegrationMethod()); - total_number_of_gauss_points += number_of_gps; - offsets[i] = total_number_of_gauss_points - number_of_gps; - } - - return total_number_of_gauss_points; - }, rUnstructuredGridData.mpCells.value()); - - // create the piece element - auto piece_element = Kratos::make_shared("Piece"); - piece_element->AddAttribute("NumberOfPoints", std::to_string(total_gauss_points)); - piece_element->AddAttribute("NumberOfCells", "0"); - unstructured_grid_element->AddElement(piece_element); - - // construct the gauss point position data - DenseVector gauss_point_nd_data_shape(2); - gauss_point_nd_data_shape[0] = total_gauss_points; - gauss_point_nd_data_shape[1] = 3; - auto gauss_point_positions = Kratos::make_shared>(gauss_point_nd_data_shape); - const auto span = gauss_point_positions->ViewData(); - - std::visit([&span, &offsets](auto p_container){ - IndexPartition(p_container->size()).for_each(array_1d{}, [&span, &p_container, &offsets](const auto Index, auto& rTLS) { - const auto& r_entity = *(p_container->begin() + Index); - const auto number_of_gauss_points = r_entity.GetGeometry().IntegrationPointsNumber(r_entity.GetIntegrationMethod()); - for (IndexType i = 0; i < number_of_gauss_points; ++i) { - r_entity.GetGeometry().GlobalCoordinates(rTLS, i); - std::copy(rTLS.begin(), rTLS.end(), span.begin() + offsets[Index] * 3 + i * 3); - } - - }); - }, rUnstructuredGridData.mpCells.value()); - - // create the gauss points element - auto points_element = Kratos::make_shared("Points"); - points_element->AddElement(p_xml_data_element_wrapper->Get("Position", gauss_point_positions)); - piece_element->AddElement(points_element); - - auto cells_element = Kratos::make_shared("Cells"); - piece_element->AddElement(cells_element); - - // create the point data - auto point_data_element = Kratos::make_shared("PointData"); - piece_element->AddElement(point_data_element); - - const auto& r_data_communicator = mrModelPart.GetCommunicator().GetDataCommunicator(); - - // add the gauss point data - bool is_gauss_point_data_available = false; - for (const auto& r_pair : integration_point_vars) { - std::visit([&offsets, &point_data_element, &p_xml_data_element_wrapper, &rUnstructuredGridData, &is_gauss_point_data_available, &r_data_communicator, total_gauss_points](auto pVariable, auto pContainer) { - // type information of the variable - using data_type = typename BareType::Type; - using data_type_traits = DataTypeTraits; - using primitive_data_type = typename data_type_traits::PrimitiveType; - - if constexpr(std::is_same_v) { - // here we cannot use GaussPointVariableTensorAdaptor because - // it does not allow recording gauss point information if different - // entities have different number of gauss points. - // hence we do the computation here manually. - - std::vector output; - - // first we need to find out the shape of the gauss point data - std::vector local_shape(data_type_traits::Dimension, 0u); - if (!pContainer->empty()) { - pContainer->front().CalculateOnIntegrationPoints( - *pVariable, output, rUnstructuredGridData.mpModelPart->GetProcessInfo()); - - if (!output.empty()) { - // if there are available gauss point information - data_type_traits::Shape(output.front(), local_shape.data(), - local_shape.data() + local_shape.size()); - } - } - - // now do the communication between ranks to get the correct size - const auto& max_local_shape = r_data_communicator.MaxAll(local_shape); - - // now we construct the nd_data_shape - DenseVector nd_data_shape(local_shape.size() + 1); - std::copy(max_local_shape.begin(), max_local_shape.end(), nd_data_shape.begin() + 1); - nd_data_shape[0] = total_gauss_points; - - const auto total_number_of_components = std::accumulate(max_local_shape.begin(), max_local_shape.end(), 1u, std::multiplies{}); - - auto p_gauss_data = Kratos::make_shared>(nd_data_shape); - auto span = p_gauss_data->ViewData(); - - if (r_data_communicator.SumAll(static_cast(span.size())) > 0) { - is_gauss_point_data_available = true; - IndexPartition(pContainer->size()).for_each(std::vector{}, [&span, &pContainer, &pVariable, &rUnstructuredGridData, &offsets, total_number_of_components](const auto Index, auto& rTLS) { - auto& r_entity = *(pContainer->begin() + Index); - r_entity.CalculateOnIntegrationPoints(*pVariable, rTLS, rUnstructuredGridData.mpModelPart->GetProcessInfo()); - DataTypeTraits>::CopyToContiguousData(span.begin() + offsets[Index] * total_number_of_components, rTLS); - }); - point_data_element->AddElement(p_xml_data_element_wrapper->Get(pVariable->Name(), p_gauss_data)); - } - } - }, r_pair.second, rUnstructuredGridData.mpCells.value()); - } - - if (is_gauss_point_data_available) { - std::stringstream output_vtu_file_name; - output_vtu_file_name - << rOutputFileNamePrefix << "/" << rUnstructuredGridData.mpModelPart->FullName() << "_" - << GetEntityName(rUnstructuredGridData.mpCells) - << "_gauss_" << Step - << (r_data_communicator.IsDistributed() - ? "_" + std::to_string(r_data_communicator.Rank()) - : "") - << ".vtu"; - - std::ofstream output_file; - output_file.open(output_vtu_file_name.str(), std::ios::out | std::ios::trunc); - output_file << "\n"; - vtk_file_element.Write(output_file); - output_file.close(); - - if (r_data_communicator.IsDistributed()) { - return std::make_pair( - rUnstructuredGridData.mpModelPart->FullName() + "_" + GetEntityName(rUnstructuredGridData.mpCells) + "_gauss", - WritePartitionedUnstructuredGridData( - *point_data_element, *Kratos::make_shared(""), - output_vtu_file_name.str(), r_data_communicator)); - } - - return std::make_pair(rUnstructuredGridData.mpModelPart->FullName() + "_" + GetEntityName(rUnstructuredGridData.mpCells) + "_gauss", - output_vtu_file_name.str()); - } - else { - return std::make_pair("", ""); - } -} - -template -void VtuOutput::WriteData( - std::vector>& rPVDFileNameInfo, - TXmlElementDataWrapperCreateFunctor&& rElementDataWrapperCreateFunctor, - TXmlElementDataWrapperAppendFunctor&& rElementDataWrapperAppendFunctor, - UnstructuredGridData& rUnstructuredGridData, - const std::string& rOutputPrefix, - const IndexType Step) const -{ - KRATOS_TRY - - rPVDFileNameInfo.push_back(WriteUnstructuredGridData( - rElementDataWrapperCreateFunctor, rElementDataWrapperAppendFunctor, - rUnstructuredGridData, rOutputPrefix, Step)); - - rPVDFileNameInfo.push_back(WriteIntegrationPointData( - rElementDataWrapperCreateFunctor, rElementDataWrapperAppendFunctor, - rUnstructuredGridData, rOutputPrefix, Step)); - - KRATOS_CATCH(""); -} - -void VtuOutput::PrintOutput(const std::string& rOutputFileNamePrefix) -{ - KRATOS_TRY - - const auto& r_process_info = mrModelPart.GetProcessInfo(); - - // here we do not check whether the r_process_info has the time variable specified - // because, in a const DataValueContainer, if the variable is not there, it returns the - // zero value of the variable. - const double time = r_process_info[TIME]; - - const IndexType step = r_process_info[STEP]; - - std::filesystem::create_directories(rOutputFileNamePrefix); - - std::vector> pvd_file_name_info; - - for (auto& r_unstructured_grid_data : mUnstructuredGridDataList) { - switch (mOutputFormat) { - case ASCII: - { - WriteData( - pvd_file_name_info, - [this](){ return Kratos::make_shared(XmlInPlaceDataElementWrapper::ASCII, this->mPrecision); }, - [](auto& rVtkFileElement, auto pXmlDataElementWrapper) {}, - r_unstructured_grid_data, - rOutputFileNamePrefix, - step); - break; - } - case BINARY: - { - WriteData( - pvd_file_name_info, - [this](){ return Kratos::make_shared(XmlInPlaceDataElementWrapper::BINARY, this->mPrecision); }, - [](auto& rVtkFileElement, auto pXmlDataElementWrapper) { rVtkFileElement.AddAttribute("header_type", "UInt64"); }, - r_unstructured_grid_data, - rOutputFileNamePrefix, - step); - break; - } - case RAW: - { - WriteData( - pvd_file_name_info, - [](){ return Kratos::make_shared(XmlAppendedDataElementWrapper::RAW); }, - [](auto& rVtkFileElement, auto pXmlDataElementWrapper) { rVtkFileElement.AddElement(pXmlDataElementWrapper); rVtkFileElement.AddAttribute("header_type", "UInt64"); }, - r_unstructured_grid_data, - rOutputFileNamePrefix, - step); - break; - } - case COMPRESSED_RAW: - { - WriteData( - pvd_file_name_info, - [](){ return Kratos::make_shared(XmlAppendedDataElementWrapper::COMPRESSED_RAW); }, - [](auto& rVtkFileElement, auto pXmlDataElementWrapper) { rVtkFileElement.AddElement(pXmlDataElementWrapper); rVtkFileElement.AddAttribute("header_type", "UInt64"); rVtkFileElement.AddAttribute("compressor", "vtkZLibDataCompressor"); }, - r_unstructured_grid_data, - rOutputFileNamePrefix, - step); - break; - } - } - } - - // now generate the *.pvd file - if (mrModelPart.GetCommunicator().MyPID() == 0) { - KRATOS_INFO_IF("VtuOutput", mEchoLevel > 1) - << "Writing \"" << mrModelPart.FullName() - << "\" PVD file...\n"; - // Single pvd file links all the vtu files from sum-model parts - // partitioned model_parts and time step vtu files together. - - if (!mIsPVDFileHeaderWritten) { - mIsPVDFileHeaderWritten = true; - - // creates the pvd file element - XmlElementsArray pvd_file_element("VTKFile"); - pvd_file_element.AddAttribute("type", "Collection"); - pvd_file_element.AddAttribute("version", "1.0"); - pvd_file_element.AddAttribute("byte_order", GetEndianness()); - - // creates the collection element - auto collection_element = Kratos::make_shared("Collection"); - pvd_file_element.AddElement(collection_element); - - // now iterate through all the time steps and correctly write - // the file names for each time step. - IndexType local_index = 0; - for (IndexType i = 0; i < pvd_file_name_info.size(); ++i) { - if (pvd_file_name_info[i].second != "") { - auto current_element = Kratos::make_shared("DataSet"); - - // write the time with the specified precision. - std::stringstream str_time; - str_time << std::scientific << std::setprecision(mPrecision) << time; - - current_element->AddAttribute("timestep", str_time.str()); - current_element->AddAttribute("name", pvd_file_name_info[i].first); - current_element->AddAttribute("part", std::to_string(local_index++)); - current_element->AddAttribute( - "file", std::filesystem::relative( - std::filesystem::absolute(pvd_file_name_info[i].second), - std::filesystem::absolute(rOutputFileNamePrefix).parent_path()) - .generic_string()); - collection_element->AddElement(current_element); - } - } - - std::ofstream output_file; - output_file.open(rOutputFileNamePrefix + ".pvd", std::ios::out | std::ios::trunc); - output_file << "\n"; - pvd_file_element.Write(output_file); - output_file.close(); - } else { - std::ofstream output_file; - output_file.open(rOutputFileNamePrefix + ".pvd", std::ios::in | std::ios::out); - output_file.seekp(-28, std::ios::end); - - // now iterate through all the time steps and correctly write - // the file names for each time step. - IndexType local_index = 0; - for (IndexType i = 0; i < pvd_file_name_info.size(); ++i) { - if (pvd_file_name_info[i].second != "") { - auto current_element = Kratos::make_shared("DataSet"); - - // write the time with the specified precision. - std::stringstream str_time; - str_time << std::scientific << std::setprecision(mPrecision) << time; - - current_element->AddAttribute("timestep", str_time.str()); - current_element->AddAttribute("name", pvd_file_name_info[i].first); - current_element->AddAttribute("part", std::to_string(local_index++)); - current_element->AddAttribute( - "file", std::filesystem::relative( - std::filesystem::absolute(pvd_file_name_info[i].second), - std::filesystem::absolute(rOutputFileNamePrefix).parent_path()) - .generic_string()); - - current_element->Write(output_file, 2); - } - } - - output_file << " \n\n"; - output_file.close(); - } - - } - - KRATOS_CATCH(""); -} - -std::string VtuOutput::Info() const -{ - std::stringstream info; - info << "VtuOutput: " << mrModelPart.FullName() << " [ writer = "; - switch (mOutputFormat) { - case ASCII: - info << "ASCII"; - break; - case BINARY: - info << "BINARY"; - break; - case RAW: - info << "RAW"; - break; - case COMPRESSED_RAW: - info << "COMPRESSED_RAW"; - break; - } - - info << ", precision = " << mPrecision << ", configuration = "; - - switch (mConfiguration){ - case Globals::Configuration::Initial: - info << "initial"; - break; - case Globals::Configuration::Current: - info << "current"; - break; - } - - info << ", echo level = " << mEchoLevel << " ]"; - - return info.str(); -} - -void VtuOutput::PrintInfo(std::ostream& rOStream) const -{ - rOStream << this->Info(); -} - -void VtuOutput::PrintData(std::ostream& rOStream) const -{ - PrintDataLocationData(rOStream, "flag", mFlags); - rOStream << "\n"; - PrintDataLocationData(rOStream, "variable", mVariables); - rOStream << "\n"; - PrintDataLocationData(rOStream, "integration variable", mIntegrationPointVariables); - rOStream << "\n"; - - rOStream << "List of model part info:"; - for (const auto& r_model_part_data : mUnstructuredGridDataList) { - rOStream << "\n\tModel part: \"" << r_model_part_data.mpModelPart->FullName() << "\"" - << " with " << GetEntityName(r_model_part_data.mpCells) << "s" - << ", used for point fields = " << (r_model_part_data.UsePointsForDataFieldOutput ? "yes" : "no"); - - if (r_model_part_data.UsePointsForDataFieldOutput) { - rOStream << "\n\t\t" << "Point fields:"; - for (const auto& r_pair : r_model_part_data.mMapOfPointTensorAdaptors) { - std::visit([&rOStream, &r_pair](auto pNDData){ - rOStream << "\n\t\t\t" << r_pair.first << ": " << *pNDData; - }, r_pair.second); - } - } - - rOStream << "\n\t\t" << "Cell fields:"; - for (const auto& r_pair : r_model_part_data.mMapOfCellTensorAdaptors) { - std::visit([&rOStream, &r_pair](auto pNDData){ - rOStream << "\n\t\t\t" << r_pair.first << ": " << *pNDData; - }, r_pair.second); - } - } -} - -// template instantiations -#ifndef KRATOS_VTU_OUTPUT_VARIABLE_METHOD_INSTANTIATION -#define KRATOS_VTU_OUTPUT_VARIABLE_METHOD_INSTANTIATION(...) \ - template KRATOS_API(KRATOS_CORE) void VtuOutput::AddVariable<__VA_ARGS__>(const Variable<__VA_ARGS__>&, const Globals::DataLocation&); \ - template KRATOS_API(KRATOS_CORE) void VtuOutput::AddIntegrationPointVariable<__VA_ARGS__>(const Variable<__VA_ARGS__>&, const Globals::DataLocation&); \ - -#endif - -#ifndef KRATOS_VTU_OUTPUT_TENSOR_METHOD_INSTANTIATION -#define KRATOS_VTU_OUTPUT_TENSOR_METHOD_INSTANTIATION(DATA_TYPE) \ - template KRATOS_API(KRATOS_CORE) void VtuOutput::AddTensorAdaptor::Pointer>(const std::string&, TensorAdaptor::Pointer); \ - template KRATOS_API(KRATOS_CORE) void VtuOutput::ReplaceTensorAdaptor::Pointer>(const std::string&, TensorAdaptor::Pointer); \ - template KRATOS_API(KRATOS_CORE) void VtuOutput::EmplaceTensorAdaptor::Pointer>(const std::string&, TensorAdaptor::Pointer); \ - -#endif - -KRATOS_VTU_OUTPUT_VARIABLE_METHOD_INSTANTIATION(int) -KRATOS_VTU_OUTPUT_VARIABLE_METHOD_INSTANTIATION(double) -KRATOS_VTU_OUTPUT_VARIABLE_METHOD_INSTANTIATION(array_1d) -KRATOS_VTU_OUTPUT_VARIABLE_METHOD_INSTANTIATION(array_1d) -KRATOS_VTU_OUTPUT_VARIABLE_METHOD_INSTANTIATION(array_1d) -KRATOS_VTU_OUTPUT_VARIABLE_METHOD_INSTANTIATION(array_1d) -KRATOS_VTU_OUTPUT_VARIABLE_METHOD_INSTANTIATION(Vector) -KRATOS_VTU_OUTPUT_VARIABLE_METHOD_INSTANTIATION(Matrix) - -KRATOS_VTU_OUTPUT_TENSOR_METHOD_INSTANTIATION(bool) -KRATOS_VTU_OUTPUT_TENSOR_METHOD_INSTANTIATION(int) -KRATOS_VTU_OUTPUT_TENSOR_METHOD_INSTANTIATION(double) - -#undef KRATOS_VTU_OUTPUT_VARIABLE_METHOD_INSTANTIATION -#undef KRATOS_VTU_OUTPUT_TENSOR_METHOD_INSTANTIATION - -} // namespace Kratos diff --git a/kratos/future/input_output/vtu_output.h b/kratos/future/input_output/vtu_output.h deleted file mode 100644 index 0dfbd6aa2dab..000000000000 --- a/kratos/future/input_output/vtu_output.h +++ /dev/null @@ -1,383 +0,0 @@ -// | / | -// ' / __| _` | __| _ \ __| -// . \ | ( | | ( |\__ ` -// _|\_\_| \__,_|\__|\___/ ____/ -// Multi-Physics -// -// License: BSD License -// Kratos default license: kratos/license.txt -// -// Main authors: Suneth Warnakulasuriya -// - -#pragma once - -// System includes -#include -#include -#include - -// External includes - -// Project includes -#include "containers/flags.h" -#include "containers/nd_data.h" -#include "containers/variable.h" -#include "includes/define.h" -#include "includes/global_variables.h" -#include "includes/io.h" -#include "includes/model_part.h" -#include "tensor_adaptors/tensor_adaptor.h" -#include "future/utilities/xml_utilities/xml_data_element_wrapper.h" - -namespace Kratos::Future { - -/** - * @class VtuOutput - * @brief Handles VTU (Visualization Toolkit Unstructured grid) output for Kratos ModelParts. - * @author Suneth Warnakulasuriya - * @ingroup KratosCore - * - * This class provides functionality to export simulation data from a Kratos ModelPart to VTU files, - * supporting both ASCII, BINARY, RAW and COMPRESSED_RAW with zlib compression. It allows users to register @ref Variable , @ref Flags , - * and @ref TensorAdaptor for output, and supports writing data on nodes, elements, conditions, and integration points. - * The output can be configured to include submodel parts and supports parallel execution (MPI). - * - * @section vtu_output_usage Usage - * This output put process can be used at any point in the simulation (static or dynamic). But, upon construction of an object of - * @ref VtuOutput, all the variables, flags, integration point variables and tensor adaptors should be added - * using @ref AddFlag, @ref AddVariable, @ref AddIntegrationPointVariable or @ref AddTensorAdaptor . Once the - * @ref PrintOutput is called, no more data fields can be added because Vtk library does not support varying fields. - * - * But, already added @ref TensorAdaptor objects may be replaced with new @ref TensorAdaptor objects after calling @ref PrintOutput - * by using @ref ReplaceTensorAdaptor method. - * - * A convenience method called @ref EmplaceTensorAdaptor is there to add the @ref TensorAdaptor if it is not existing and if the call is - * before the first call of @ref PrintOutput. Otherwise, it will try replacing an existing @ref TensorAdaptor. - * - */ -class KRATOS_API(KRATOS_CORE) VtuOutput : public IO -{ -public: - ///@name Type definitions - ///@{ - - // Index type definition - using IndexType = std::size_t; - - // Variant defining supported container (i.e. @ref PointerVectorSet ) type pointers. - using SupportedContainerPointerType = std::variant< - ModelPart::NodesContainerType::Pointer, - ModelPart::ConditionsContainerType::Pointer, - ModelPart::ElementsContainerType::Pointer - >; - - // Variant defining supported cell type @ref PointerVectorSte which can be visualized with cell data with vtk library. - using CellContainerPointerType = std::variant< - ModelPart::ConditionsContainerType::Pointer, - ModelPart::ElementsContainerType::Pointer - >; - - // Variant defining all the @ref Variable types which are supported to be visualized at point or cell data with vtk library. - using SupportedVariablePointerType = std::variant< - Variable const *, - Variable const *, - Variable> const *, - Variable> const *, - Variable> const *, - Variable> const *, - Variable const *, - Variable const * - >; - - // Variant definining all the supported @ref TensorAdaptor which can be used to pass data fields to point or cell data using the vtk library. - using SupportedTensorAdaptorPointerType = std::variant< - TensorAdaptor::Pointer, - TensorAdaptor::Pointer, - TensorAdaptor::Pointer - >; - - - // A list of maps of name and a @p T for different locations ( @ref Globals::DataLocation ) which are used for output at later time. - template - using DataList = std::array, static_cast(Kratos::Globals::DataLocation::NumberOfDataLocations)>; - - KRATOS_CLASS_POINTER_DEFINITION(VtuOutput); - - ///@} - ///@name Public enums - ///@{ - - /// Enumerations for the output writer format. - enum WriterFormat - { - ASCII, ///< ASCII format. - BINARY, ///< Binary format. - RAW, ///< Raw format. All data is appended to one stream. - COMPRESSED_RAW ///< Data is first compressed with zlib and the appended to one stream. - }; - - struct UnstructuredGridData - { - bool UsePointsForDataFieldOutput; // If true, then the mpPoints represents a container in the model part, otherwise, mpPoints refers to a container which is on the fly generated. - ModelPart * mpModelPart; // Model part associated with the unstructured grid data. - ModelPart::NodesContainerType::Pointer mpPoints; // Points to be used in the unstructured grid. - std::optional mpCells; // Cells to be used in the unstructured grid. - std::map mMapOfPointTensorAdaptors; // Point data tensor adaptors. - std::map mMapOfCellTensorAdaptors; // Cell data tensor adaptors. - }; - - ///@} - ///@name Life cycle - ///@{ - - /** - * @brief Construct a new Vtu Output - * - * @param rModelPart Model part to be used in the vtu output. - * @param Configuration Which nodal positions to be written out. - * @param OutputFormat The format of the output. - * @param Precision Precision of the double values to be used when writing the doubles as ASCII. - * @param OutputSubModelParts To consider all the submodel parts recursively for output. - * @param WriteIds To write ids under the name "KRATOS_ID" to be visualized. - * @param EchoLevel Echo level for to print information. - */ - VtuOutput( - ModelPart& rModelPart, - const Globals::Configuration Configuration, - const WriterFormat OutputFormat = WriterFormat::COMPRESSED_RAW, - const IndexType Precision = 9, - const bool OutputSubModelParts = false, - const bool WriteIds = false, - const IndexType EchoLevel = 0); - - ///@} - ///@name Public operations - ///@{ - - /** - * @brief Adds a flag to the VTU output. - * - * This method registers a flag @p rFlagVariable to be included in the VTU output file. - * The flag will be associated with the specified data location (e.g., node, element, condition, refer @ref Globals::DataLocation ) - * given by @p DataLocation . This allows the Flag's values to be written to the output file - * when @ref PrintOutput is called with the name @p rFlagName. - * - * @throws std::runtime_error if @ref AddFlag is called after @ref PrintOutput. - * @throws std::runtime_error if tries to add the same @p rFlagName more than ones. - * @throws std::runtime_error if there already exist a field name same as @p rFlagName in one of the compatible data locations with @p DataLocation . - * @throws std::runtime_error if @p DataLocation is not NodeNonHistorical, Condition, or Element. - * - * @param rFlagName The name of the flag to be added. - * @param rFlagVariable The flag variable to be added. - * @param DataLocation The location where the flag data is stored (e.g., NodeNonHistorical, Condition, Element). - * - * @see @ref FlagsTensorAdaptor - */ - void AddFlag( - const std::string& rFlagName, - const Flags& rFlagVariable, - const Globals::DataLocation& DataLocation); - - /** - * @brief Adds a variable to the output for a specified data location. - * - * Registers the given @p rVariable to be included in the VTU output at the specified - * @p DataLocation (e.g., NodeHistorical, NodeNonHistorical, Condition, or Element, refer @ref Globals::DataLocation). - * This allows the variable's values to be written to the output file when @ref PrintOutput is called. - * - * @throws std::runtime_error if @ref AddVariable is called after @ref PrintOutput. - * @throws std::runtime_error if tries to add the same @p rVariable more than ones. - * @throws std::runtime_error if there already exist a field name same as @p rVariable in one of the compatible data locations with @p DataLocation . - * @throws std::runtime_error if @p DataLocation is not NodeHistorical, NodeNonHistorical, Condition, or Element. - * - * @tparam TDataType Data type of the variable. - * @param rVariable Variable to be added. - * @param DataLocation The location in the model where the variable is defined (e.g., NodeHistorical, NodeNonHistorical, Condition, or Element). - * - * @see @ref VariableTensorAdaptor - * @see @ref HistoricalVariableTensorAdaptor - */ - template - void AddVariable( - const Variable& rVariable, - const Globals::DataLocation& DataLocation); - - /** - * @brief Adds a variable to be output at integration points. - * - * This method registers a @p rVariable for output at the integration points of the mesh elements or conditions - * specified by @p DataLocation (refer @ref Globals::DataLocation ). This allows the entities variable's integration point values to - * be written to the output file when @ref PrintOutput is called. - * - * @throws std::runtime_error if @ref AddIntegrationPointVariable is called after @ref PrintOutput. - * @throws std::runtime_error if tries to add the same @p rVariable more than ones. - * @throws std::runtime_error if there already exist a field name same as @p rVariable in one of the compatible data locations with @p DataLocation . - * @throws std::runtime_error if @p DataLocation is not Condition or Element. - * - * @tparam TDataType Data type of the variable. - * @param rVariable Variable to be added. - * @param DataLocation Specifies the location (e.g., Condition or Element) where the variable is used to calculate integration point values. - */ - template - void AddIntegrationPointVariable( - const Variable& rVariable, - const Globals::DataLocation& DataLocation); - - /** - * @brief Adds a tensor adaptor to the output. - * - * Registers a @p pTensorAdaptor with the specified @p TensorAdaptorName for the the vtu output. this does not - * copy the tensor adaptor. When @ref PrintOutput is called, the values of the @p pTensorAdaptor at this point will - * be written to vtu. - * - * @throws std::runtime_error if @ref AddTensorAdaptor is called after @ref PrintOutput. - * @throws std::runtime_error if tries to add the same @p rTensorAdaptorName more than ones. - * @throws std::runtime_error if there already exist a field name same as @p rTensorAdaptorName in one of the compatible data locations represented by the container of @p pTensorAdaptor . - * @throws std::runtime_error if @p pTensorAdaptor does not corresponds to any of the containers which is written by this @ref VtuOutput . - * - * @tparam TTensorAdaptorPointerType Pointer type of the tensor adaptor. - * @param rTensorAdaptorName The name to associate with the tensor adaptor. - * @param pTensorAdaptor Pointer to the tensor adaptor to be added. - */ - template - void AddTensorAdaptor( - const std::string& rTensorAdaptorName, - TTensorAdaptorPointerType pTensorAdaptor); - - /** - * @brief Updates the tensor adaptor associated with the given name. - * - * This method assigns a new tensor adaptor to the specified name, allowing - * for dynamic changes to the tensor adaptor used in the @ref VtuOutput process. - * This also copies the internal data of @p pTensorAdaptor to vtu output's internal data. - * - * @throws std::runtime_error if there is no field name same as @p rTensorAdaptorName in one of the compatible data locations represented by the container of @p pTensorAdaptor . - * @throws std::runtime_error if @p pTensorAdaptor does not corresponds to any of the containers which is written by this @ref VtuOutput . - * - * @tparam TTensorAdaptorPointerType Pointer type of the tensor adaptor. - * @param rTensorAdaptorName The name identifying the tensor adaptor to update. - * @param pTensorAdaptor Pointer to the new tensor adaptor to be associated. - */ - template - void ReplaceTensorAdaptor( - const std::string& rTensorAdaptorName, - TTensorAdaptorPointerType pTensorAdaptor); - - /** - * @brief Inserts a @ref TensorAdaptor into the internal storage with the specified name. - * - * This method: - * - If PrintOutput is not called at all, then calls @ref AddTensorAdaptor - * - If PrintOutput is at least once called, then calls @ref ReplaceTensorAdaptor - * - * @tparam TTensorAdaptorPointerType Pointer type of the tensor adaptor. - * @param rTensorAdaptorName The name to associate with the @ref TensorAdaptor. - * @param pTensorAdaptor Pointer to the @ref TensorAdaptor to be stored. - */ - template - void EmplaceTensorAdaptor( - const std::string& rTensorAdaptorName, - TTensorAdaptorPointerType pTensorAdaptor); - - /** - * @brief Returns the model part. - * @return The constant reference to the model part. - */ - const ModelPart& GetModelPart() const; - - /** - * @brief Get the list of output containers - * @details This method returns containers of the model part which are used when writing fields. - * @return std::vector List of container which are used in when writing fields. - */ - std::vector GetOutputContainerList() const; - - /** - * @brief Prints the vtu output data to a file with the specified filename prefix. - * - * Will create the folder with the provided @p rOutputFilenamePrefix . In this folder, following files will be created. - * - One vtu file per timestep, per model part's container (Including sub model parts if @p OutputSubModelParts is true) (in MPI, per rank as well). - * - If it find any gauss point fields, then there will be a vtu file per time step, per model part's container (in MPI, per rank as well). - * - If this is called in MPI, then this will create one pvtu file per timestep, per model part's container (will be having information of all the corresponding rank vtu files) - * - If this is called in MPI, then this will create one pvtu file per timestep, per model part's gauss point container (will be having information of all the corresponding rank vtu files) - * - * Finally it will create one pvd ( @p rOutputFilenamePrefix .pvd ) file for all the model parts, all the timesteps all the gauss point container linking - * - In MPI the pvtu files created. - * - In shared memory parallelism the vtu files created. - * - * @param rOutputFilenamePrefix The prefix to use for the output filename. - */ - void PrintOutput(const std::string& rOutputFilenamePrefix); - - ///@} - ///@name Input and output - ///@{ - - /// Turn back information as a string. - std::string Info() const override; - - /// Print information about this object. - void PrintInfo(std::ostream& rOStream) const override; - - /// Print object's data. - void PrintData(std::ostream& rOStream) const override; - - ///@} - -private: - ///@name Private member variables - ///@{ - - bool mIsPVDFileHeaderWritten; - - ModelPart& mrModelPart; - - const Globals::Configuration mConfiguration; - - const IndexType mEchoLevel; - - const WriterFormat mOutputFormat; - - const IndexType mPrecision; - - DataList mFlags; - - DataList mVariables; - - DataList mIntegrationPointVariables; - - std::vector mUnstructuredGridDataList; - - ///@} - ///@name Private operations - ///@{ - - template - void WriteData( - std::vector>& rPVDFileNameInfo, - TXmlElementDataWrapperCreateFunctor&& rElementDataWrapperCreateFunctor, - TXmlElementDataWrapperAppendFunctor&& rElementDataWrapperAppendFunctor, - UnstructuredGridData& rUnstructuredGridData, - const std::string& rOutputPrefix, - const IndexType Step) const; - - template - std::pair WriteUnstructuredGridData( - TXmlElementDataWrapperCreateFunctor&& rElementDataWrapperCreateFunctor, - TXmlElementDataWrapperAppendFunctor&& rElementDataWrapperAppendFunctor, - UnstructuredGridData& rUnstructuredGridData, - const std::string& rOutputPrefix, - const IndexType Step) const; - - template - std::pair WriteIntegrationPointData( - TXmlElementDataWrapperCreateFunctor&& rElementDataWrapperCreateFunctor, - TXmlElementDataWrapperAppendFunctor&& rElementDataWrapperAppendFunctor, - UnstructuredGridData& rUnstructuredGridData, - const std::string& rOutputPrefix, - const IndexType Step) const; - - ///@} -}; -} // namespace Kratos::Future diff --git a/kratos/input_output/vtu_output.cpp b/kratos/input_output/vtu_output.cpp index 249f9be2b7c4..52b9f1492b75 100644 --- a/kratos/input_output/vtu_output.cpp +++ b/kratos/input_output/vtu_output.cpp @@ -11,831 +11,1733 @@ // // System includes -#include -#include +#include +#include #include +#include // External includes // Project includes -#include "expression/container_data_io.h" -#include "expression/container_expression.h" -#include "expression/literal_flat_expression.h" -#include "expression/variable_expression_io.h" #include "includes/data_communicator.h" #include "input_output/base_64_encoded_output.h" #include "input_output/vtk_definitions.h" -#include "utilities/global_pointer_utilities.h" +#include "tensor_adaptors/flags_tensor_adaptor.h" +#include "tensor_adaptors/historical_variable_tensor_adaptor.h" +#include "tensor_adaptors/node_position_tensor_adaptor.h" +#include "tensor_adaptors/variable_tensor_adaptor.h" +#include "utilities/container_io_utils.h" +#include "utilities/data_type_traits.h" #include "utilities/parallel_utilities.h" -#include "utilities/pointer_communicator.h" +#include "utilities/reduction_utilities.h" #include "utilities/string_utilities.h" -#include "utilities/xml_utilities/xml_expression_element.h" -#include "utilities/xml_utilities/xml_ostream_ascii_writer.h" -#include "utilities/xml_utilities/xml_ostream_base64_binary_writer.h" +#include "utilities/xml_utilities/xml_appended_data_element_wrapper.h" +#include "utilities/xml_utilities/xml_elements_array.h" +#include "utilities/xml_utilities/xml_in_place_data_element_wrapper.h" +#include "utilities/xml_utilities/xml_utils.h" // Include base h #include "vtu_output.h" namespace Kratos { - KRATOS_CREATE_LOCAL_FLAG(VtuOutput, NODES, 1); - KRATOS_CREATE_LOCAL_FLAG(VtuOutput, CONDITIONS, 2); - KRATOS_CREATE_LOCAL_FLAG(VtuOutput, ELEMENTS, 3); +namespace { -namespace VtuOutputHelperUtilities { +std::string GetEndianness() +{ + int i = 0x0001; -Expression::ConstPointer CreatePositionsExpression( - const ModelPart::NodesContainerType& rNodes, - const bool IsInitialConfiguration) -{ - auto p_position_expression = LiteralFlatExpression::Create(rNodes.size(), {3}); - auto& r_position_expression = *p_position_expression; - - if (IsInitialConfiguration) { - IndexPartition(rNodes.size()).for_each([&r_position_expression, &rNodes](const IndexType Index) { - const auto& r_coordinates = (rNodes.begin() + Index)->GetInitialPosition().Coordinates(); - const IndexType start_index = Index * 3; - r_position_expression.SetData(start_index, 0, r_coordinates[0]); - r_position_expression.SetData(start_index, 1, r_coordinates[1]); - r_position_expression.SetData(start_index, 2, r_coordinates[2]); - }); + if (*reinterpret_cast(&i) != 0) { + return "LittleEndian"; } else { - IndexPartition(rNodes.size()).for_each([&r_position_expression, &rNodes](const IndexType Index) { - const auto& r_coordinates = (rNodes.begin() + Index)->Coordinates(); - const IndexType start_index = Index * 3; - r_position_expression.SetData(start_index, 0, r_coordinates[0]); - r_position_expression.SetData(start_index, 1, r_coordinates[1]); - r_position_expression.SetData(start_index, 2, r_coordinates[2]); - }); + return "BigEndian"; } +} - return p_position_expression; +template +void CheckDataArrayName( + const std::string& rName, + const Globals::DataLocation& rLocation, + const VtuOutput::DataList& rList) +{ + KRATOS_TRY + + KRATOS_ERROR_IF(rList[static_cast(rLocation)].find(rName) != rList[static_cast(rLocation)].end()) + << "Found an existing data array with the same name = \"" << rName << "\".\n"; + + KRATOS_CATCH(""); } -XmlExpressionElement::Pointer CreateDataArrayElement( - const std::string& rDataArrayName, - const std::vector& rExpressions) +void CheckDataArrayName( + const std::string& rName, + const Globals::DataLocation& rLocation, + const VtuOutput::UnstructuredGridData& rUnstructuredGridData) { - std::vector expressions; - for (const auto& p_expression : rExpressions) { - if (p_expression) { - expressions.push_back(p_expression); - } + KRATOS_TRY + + bool found_existing_name = false; + switch (rLocation) { + case Globals::DataLocation::NodeHistorical: + case Globals::DataLocation::NodeNonHistorical: + // The following code block will be executed for Globals::DataLocation::NodeHistorical and Globals::DataLocation::NodeNonHistorical. + found_existing_name = rUnstructuredGridData.mMapOfPointTensorAdaptors.find(rName) != rUnstructuredGridData.mMapOfPointTensorAdaptors.end(); + break; + case Globals::DataLocation::Condition: + case Globals::DataLocation::Element: + // The following code block will be executed for Globals::DataLocation::Condition and Globals::DataLocation::Element. + found_existing_name = rUnstructuredGridData.mMapOfCellTensorAdaptors.find(rName) != rUnstructuredGridData.mMapOfCellTensorAdaptors.end(); + break; + default: + KRATOS_ERROR << "Unsupported data location type."; } - if (expressions.size() > 0) { - return Kratos::make_shared(rDataArrayName, expressions); - } else { - return nullptr; + + KRATOS_ERROR_IF(found_existing_name) + << "Found an existing data array with the same name = \"" << rName << "\".\n"; + + KRATOS_CATCH(""); +} + +void CheckDataArrayName( + const std::string& rName, + const Globals::DataLocation& rLocation, + const std::vector& rListOfUnstructuredGridData) +{ + KRATOS_TRY + + for (const auto& r_model_part_data : rListOfUnstructuredGridData) { + switch (rLocation) { + case Globals::DataLocation::NodeHistorical: + case Globals::DataLocation::NodeNonHistorical: + // The following code block will be executed for Globals::DataLocation::NodeHistorical and Globals::DataLocation::NodeNonHistorical. + if (r_model_part_data.UsePointsForDataFieldOutput) { + CheckDataArrayName(rName, rLocation, r_model_part_data); + } + break; + default: + CheckDataArrayName(rName, rLocation, r_model_part_data); + } } + + KRATOS_CATCH(""); } -template -const Expression* pGetExpression(const ContainerExpression& rContainerExpression) +std::string GetEntityName(const std::optional& pCellContainer) { - if (rContainerExpression.HasExpression()) { - return &*rContainerExpression.pGetExpression(); + if (pCellContainer.has_value()) { + return std::visit([](auto p_cell_container) { + using container_type = BareType; + return ModelPart::Container::GetEntityName(); + }, pCellContainer.value()); } else { - return nullptr; + return "node"; } } -void AddDataArrayElement( - XmlExpressionElement::Pointer pParentElement, - XmlExpressionElement::Pointer pDataArrayElement) +void CopyAttributes( + const XmlElement& rSource, + XmlElement& rDestination) { - if (pDataArrayElement) { - pParentElement->AddElement(pDataArrayElement); + for (const auto& [attribute, value] : rSource.GetAttributes()) { + rDestination.AddAttribute(attribute, value); } } -XmlExpressionElement::Pointer CreatePointsXmlElement( - const ModelPart& rModelPart, - const bool IsInitialConfiguration) +template +NDDataPointerType GetWritingNDData( + const std::vector& rWritingIndices, + NDDataPointerType pNDData) { - auto p_points_xml_element = Kratos::make_shared("Points"); + KRATOS_TRY - const auto& r_communicator = rModelPart.GetCommunicator(); - const auto& r_local_nodes = r_communicator.LocalMesh().Nodes(); - const auto& r_ghost_nodes = r_communicator.GhostMesh().Nodes(); + const auto& origin_shape = pNDData->Shape(); - auto local_position = CreatePositionsExpression(r_local_nodes, IsInitialConfiguration); - auto ghost_position = CreatePositionsExpression(r_ghost_nodes, IsInitialConfiguration); + KRATOS_ERROR_IF(origin_shape.size() == 0) + << "NDData shape should have at least one dimension representing number of entities [ nd data = " + << *pNDData << " ].\n"; - AddDataArrayElement( - p_points_xml_element, - CreateDataArrayElement("Position", {&*local_position, &*ghost_position})); + if (rWritingIndices.size() == origin_shape[0]) { + // number of writing indices are same as the first dimension of the NdData, hence + // there is nothing to be ignored from this data set. Returning the original + return pNDData; + } else { + // now there is a mismatch between number of writing indices and the number of entities represented by the pNDData. + // Hence we continue with copying data. - return p_points_xml_element; -} + // data type of the NDData, may be unsigned char, int, bool, double + using data_type = typename BareType::DataType; -template -LiteralFlatExpression::Pointer CreateOffsetsExpression(const TContainerType& rContainer) -{ - auto p_offsets_expression = LiteralFlatExpression::Create(rContainer.size(), {}); - auto data_itr = p_offsets_expression->begin(); + // compute number of components for each entity. + const auto number_of_components = std::accumulate(origin_shape.begin() + 1, origin_shape.end(), 1u, std::multiplies{}); + + // construct the new NDData holder having only the data from writing indices. + DenseVector destination_shape(origin_shape); + destination_shape[0] = rWritingIndices.size(); + auto p_destination_nd_data = Kratos::make_shared>(destination_shape); + + // get spans + const auto& origin_span = pNDData->ViewData(); + auto destination_span = p_destination_nd_data->ViewData(); + + // now copy the data + IndexPartition(rWritingIndices.size()).for_each([&origin_span, &destination_span, &rWritingIndices, number_of_components](const auto Index) { + auto orig_itr = origin_span.begin() + rWritingIndices[Index] * number_of_components; + auto dest_itr = destination_span.begin() + Index * number_of_components; + std::copy(orig_itr, orig_itr + number_of_components, dest_itr); + }); - IndexType total_offset = 0; - for (const auto& r_entity : rContainer) { - total_offset += r_entity.GetGeometry().size(); - *(data_itr++) = total_offset; + return p_destination_nd_data; } - return p_offsets_expression; + + KRATOS_CATCH(""); } template -Expression::Pointer CreateGeometryTypesExpression(const TContainerType& rContainer) +NDData::Pointer GetGeometryTypes( + std::vector& rWritingIndices, + const TContainerType& rContainer, + const IndexType EchoLevel) { - auto p_geometry_expression = LiteralFlatExpression::Create(rContainer.size(), {}); - auto data_itr = p_geometry_expression->begin(); + auto p_geometry_types = Kratos::make_shared>(DenseVector(1, rContainer.size())); + auto span = p_geometry_types->ViewData(); + + DenseVector ignored_indices(rContainer.size(), 0); + + IndexPartition(rContainer.size()).for_each([&span, &rContainer, &ignored_indices, EchoLevel](const IndexType Index) { - IndexPartition(rContainer.size()).for_each([data_itr, &rContainer](const IndexType Index) { const auto p_itr = VtkDefinitions::KratosVtkGeometryTypes.find((rContainer.begin() + Index)->GetGeometry().GetGeometryType()); if (p_itr != VtkDefinitions::KratosVtkGeometryTypes.end()) { - *(data_itr + Index) = p_itr->second; + *(span.begin() + Index) = static_cast(p_itr->second); } else { - KRATOS_ERROR << "Element with id " << (rContainer.begin() + Index)->Id() << " has unsupported geometry."; + ignored_indices[Index] = 1; + KRATOS_WARNING_IF("VtuOutput", EchoLevel > 1) + << "Skipping unsupported geometry type in " + << ModelPart::Container::GetEntityName() + << " with id " << (rContainer.begin() + Index)->Id() << ".\n"; } }); - return p_geometry_expression; + + // fill in the writing indices + rWritingIndices.reserve(rContainer.size()); + for (IndexType i = 0; i < rContainer.size(); ++i) { + if (ignored_indices[i] != 1) { + rWritingIndices.push_back(i); + } + } + + return p_geometry_types; +} + +template +NDData::Pointer GetOffsets( + const std::vector& rWritingIndices, + const TContainerType& rContainer) +{ + auto p_offsets = Kratos::make_shared>(DenseVector(1, rWritingIndices.size())); + auto data_itr = p_offsets->ViewData().begin(); + + int total_offset = 0; + for (IndexType i = 0; i < rWritingIndices.size(); ++i) { + total_offset += (rContainer.begin() + rWritingIndices[i])->GetGeometry().size(); + data_itr[i] = total_offset; + } + + return p_offsets; } template -Expression::Pointer CreateConnectivityExpression( - const LiteralFlatExpression::Pointer pOffsetsExpression, +NDData::Pointer GetConnectivities( + const NDData& rOffsets, const TContainerType& rContainer, - const std::unordered_map& rKratosVtuIndicesMap) + const std::unordered_map& rKratosVtuIndicesMap, + const std::vector& rWritingIndices) { - auto offset_data_itr = pOffsetsExpression->begin(); + if (rOffsets.Size() == 0) { + return Kratos::make_shared>(DenseVector(1, 0)); + } - auto p_connectivity_expression = LiteralFlatExpression::Create(*(offset_data_itr + rContainer.size() - 1), {}); - auto data_itr = p_connectivity_expression->begin(); + const auto offsets_span = rOffsets.ViewData(); + auto p_connectivities = Kratos::make_shared>(DenseVector(1, offsets_span.back())); + auto connectivities_span = p_connectivities->ViewData(); - IndexPartition(rContainer.size()).for_each([data_itr, offset_data_itr, &rContainer, &rKratosVtuIndicesMap](const IndexType Index) { - const auto& r_geometry = (rContainer.begin() + Index)->GetGeometry(); - auto entity_data_begin_itr = data_itr + *(offset_data_itr + Index) - r_geometry.size(); + IndexPartition(rWritingIndices.size()).for_each([&connectivities_span, &offsets_span, &rContainer, &rKratosVtuIndicesMap, &rWritingIndices](const IndexType Index) { + const auto& r_geometry = (rContainer.begin() + rWritingIndices[Index])->GetGeometry(); + auto entity_data_begin_itr = connectivities_span.begin() + offsets_span[Index] - r_geometry.size(); - for (const auto& r_node : r_geometry) { - const auto p_itr = rKratosVtuIndicesMap.find(r_node.Id()); + for (IndexType i_node = 0; i_node < r_geometry.size(); ++i_node) { + const auto p_itr = rKratosVtuIndicesMap.find(r_geometry[i_node].Id()); if (p_itr != rKratosVtuIndicesMap.end()) { - *(entity_data_begin_itr++) = p_itr->second; + entity_data_begin_itr[i_node] = p_itr->second; } else { - KRATOS_ERROR << "Node with id " << r_node.Id() << " not found in nodes list."; + KRATOS_ERROR << "Node with id " << r_geometry[i_node].Id() << " not found in nodes list."; } } }); - return p_connectivity_expression; + + return p_connectivities; } -template -XmlExpressionElement::Pointer CreateCellsXmlElement( - const TContainerType& rContainer, - const std::unordered_map& rKratosVtuIndicesMap) +template +void AddConnectivityData( + XmlElementsArray& rCellElement, + std::vector& rWritingIndices, + const ModelPart::NodesContainerType& rNodes, + VtuOutput::CellContainerPointerType pCells, + TXmlDataElementWrapper& rXmlDataElementWrapper, + const IndexType EchoLevel) { - auto p_cells_xml_element = Kratos::make_shared("Cells"); + std::visit([&rCellElement, &rXmlDataElementWrapper, &rWritingIndices, &rNodes, EchoLevel](auto p_container) { + std::unordered_map indices_map; + indices_map.reserve(rNodes.size()); + IndexType vtu_index = 0; + for (const auto& r_node : rNodes) { + indices_map[r_node.Id()] = vtu_index++; + } - auto p_offsets_expression = CreateOffsetsExpression(rContainer); - auto p_connectivity_expression = CreateConnectivityExpression(p_offsets_expression, rContainer, rKratosVtuIndicesMap); - auto p_geometry_type_expression = CreateGeometryTypesExpression(rContainer); + KRATOS_INFO_IF("VtuOutput", EchoLevel > 2) << "------ Collecting Vtk geometry type info...\n"; + auto p_type_data = GetGeometryTypes(rWritingIndices, *p_container, EchoLevel); - AddDataArrayElement( - p_cells_xml_element, - CreateDataArrayElement("connectivity", {&*p_connectivity_expression})); - AddDataArrayElement(p_cells_xml_element, - CreateDataArrayElement("offsets", {&*p_offsets_expression})); - AddDataArrayElement(p_cells_xml_element, - CreateDataArrayElement("types", {&*p_geometry_type_expression})); - return p_cells_xml_element; + KRATOS_INFO_IF("VtuOutput", EchoLevel > 2) << "------ Ignored " << (p_container->size() - rWritingIndices.size()) << "/" + << p_container->size() << " " << GetEntityName(p_container) << "(s).\n"; + + KRATOS_INFO_IF("VtuOutput", EchoLevel > 2) << "------ Collecting geometry offsets info...\n"; + auto p_offsets = GetOffsets(rWritingIndices, *p_container); + + KRATOS_INFO_IF("VtuOutput", EchoLevel > 2) << "------ Collecting geometry connectivity info...\n"; + rCellElement.AddElement(rXmlDataElementWrapper.Get("connectivity", GetConnectivities(*p_offsets, *p_container, indices_map, rWritingIndices))); + rCellElement.AddElement(rXmlDataElementWrapper.Get("offsets", p_offsets)); + rCellElement.AddElement(rXmlDataElementWrapper.Get("types", GetWritingNDData(rWritingIndices, p_type_data))); + }, pCells); } -template -XmlExpressionElement::Pointer CreateVariableDataXmlElement( +template +void AddFieldsUsingTensorAdaptorImpl( + XmlElementsArray& rXmlElement, + TContainerPointerType pContainer, const Variable& rVariable, - ModelPart& rModelPart) + TXmlDataElementWrapper& rXmlDataElementWrapper, + const DataCommunicator& rDataCommunicator, + const std::vector& rWritingIndices, + const IndexType EchoLevel, + TArgs&&... rArgs) { - if constexpr(std::is_same_v) { - ContainerExpression local_container(rModelPart); - if constexpr(std::is_same_v) { - VariableExpressionIO::Read(local_container, &rVariable, true); + KRATOS_TRY + + + using primitive_data_type = typename DataTypeTraits::PrimitiveType; + + if constexpr(std::is_same_v) { + // we only support int variable, and there are no TensorAdaptors to + // collect data from integer variables, we do it manually here. + auto p_nd_data = Kratos::make_shared>(DenseVector(1, pContainer->size())); + const auto& shape = p_nd_data->Shape(); + if constexpr (std::is_same_v) { + ContainerIOUtils::CopyToContiguousArray( + *pContainer, p_nd_data->ViewData(), + shape.data().begin(), shape.data().begin() + 1, + [&rVariable](int& rValue, const Node& rNode) { + rValue = rNode.FastGetSolutionStepValue(rVariable); + }); + } else if constexpr(std::is_same_v) { + ContainerIOUtils::CopyToContiguousArray( + *pContainer, p_nd_data->ViewData(), + shape.data().begin(), shape.data().begin() + 1, + [&rVariable](int& rValue, const auto& rNode) { + rValue = rNode.GetValue(rVariable); + }); } else { - VariableExpressionIO::Read(local_container, &rVariable, false); + KRATOS_ERROR << "Unsupported tensor adaptor type."; } - if (rModelPart.GetCommunicator().GhostMesh().NumberOfNodes() > 0) { - ContainerExpression ghost_container(rModelPart); - if constexpr(std::is_same_v) { - VariableExpressionIO::Read(ghost_container, &rVariable, true); - } else { - VariableExpressionIO::Read(ghost_container, &rVariable, false); + // since we only support Variable, which is having a static data shape + // we don't have to do mpi communication to decide the shape on the + // empty ranks. + rXmlElement.AddElement(rXmlDataElementWrapper.Get(rVariable.Name(), GetWritingNDData(rWritingIndices, p_nd_data))); + } else if constexpr(std::is_same_v) { + using data_type_traits = DataTypeTraits; + + if constexpr(data_type_traits::IsDynamic) { + // this is a dynamic type such as Vector or Matrix, so + // we need to do communication to decide the correct size + // because, there may be ranks with zero entities, hence these ranks will not have + // correctly sized dynamic Matrix or Vectors. Vtu needs all the ranks to have the same number + // of components, hence communication is a must in here. + + // construct the correct data_shape + std::vector data_shape(data_type_traits::Dimension, 0); + + if (!pContainer->empty()) { + // if the container is not empty. + TTensorAdaptorType tensor_adaptor(pContainer, &rVariable, rArgs...); + tensor_adaptor.CollectData(); + + const auto& ta_shape = tensor_adaptor.Shape(); + std::copy(ta_shape.begin() + 1, ta_shape.end(), data_shape.begin()); + + // create the xml element in ranks which do have entities. + rXmlElement.AddElement(rXmlDataElementWrapper.Get(rVariable.Name(), GetWritingNDData(rWritingIndices, tensor_adaptor.pGetStorage()))); } - return CreateDataArrayElement( - rVariable.Name(), - {pGetExpression(local_container), pGetExpression(ghost_container)}); + // communicate to identify the correct data shape to be written down to ranks which + // do not have any entities. + const auto& max_data_shape = rDataCommunicator.MaxAll(data_shape); + + if (pContainer->empty()) { + // if the container is empty, now create an empty NDData with correct data shape. + DenseVector nd_shape(max_data_shape.size() + 1); + std::copy(max_data_shape.begin(), max_data_shape.end(), nd_shape.begin() + 1); + nd_shape[0] = pContainer->size(); + auto p_nd_data = Kratos::make_shared(nd_shape); + + // create the xml element in ranks which do not have any entities. + rXmlElement.AddElement(rXmlDataElementWrapper.Get(rVariable.Name(), p_nd_data)); + } } else { - return CreateDataArrayElement( - rVariable.Name(), - {pGetExpression(local_container)}); + // this is a static type such as double, array_1d, ... + // So no need of mpi communication + TTensorAdaptorType tensor_adaptor(pContainer, &rVariable, rArgs...); + tensor_adaptor.CollectData(); + rXmlElement.AddElement(rXmlDataElementWrapper.Get(rVariable.Name(), GetWritingNDData(rWritingIndices, tensor_adaptor.pGetStorage()))); } - } else { - ContainerExpression local_container(rModelPart); - VariableExpressionIO::Read(local_container, &rVariable); - - return CreateDataArrayElement(rVariable.Name(), {pGetExpression(local_container)}); + KRATOS_ERROR << "Unsupported variable type."; } + + KRATOS_CATCH(""); } -template -Expression::Pointer CreateContainerFlagExpression( - const TContainerType& rContainer, - const Flags& rFlag) +template +void AddFieldsUsingTensorAdaptor( + XmlElementsArray& rXmlElement, + TContainerPointerType pContainer, + const TMapType& rMap, + TXmlDataElementWrapper& rXmlDataElementWrapper, + const DataCommunicator& rDataCommunicator, + const std::vector& rWritingIndices, + const IndexType EchoLevel, + TArgs&&... rArgs) { - auto p_flag_expression = LiteralFlatExpression::Create(rContainer.size(), {}); - auto data_itr = p_flag_expression->begin(); - - IndexPartition(rContainer.size()).for_each([data_itr, &rContainer, &rFlag](const IndexType Index) { - *(data_itr + Index) = (rContainer.begin() + Index)->Is(rFlag); - }); + KRATOS_TRY + + for (const auto& r_pair : rMap) { + using data_type = BareType; + + KRATOS_INFO_IF("VtuOutput", EchoLevel > 2) << "------ Collecting " << r_pair.first << " data...\n"; + + if constexpr(std::is_same_v) { + if (r_pair.first == "KRATOS_ID") { + // this is specific to write KRATOS_IDS. + auto p_nd_data = Kratos::make_shared>(DenseVector(1, rWritingIndices.size())); + auto span = p_nd_data->ViewData(); + IndexPartition(rWritingIndices.size()).for_each([&pContainer, &span, &rWritingIndices](const auto Index) { + span[Index] = (pContainer->begin() + rWritingIndices[Index])->Id(); + }); + rXmlElement.AddElement(rXmlDataElementWrapper.Get(r_pair.first, p_nd_data)); + } else { + // the map is of type flags + // here we don't need to do any communication because Flags are always having a static data shape. + TTensorAdaptorType tensor_adaptor(pContainer, *r_pair.second, rArgs...); + tensor_adaptor.CollectData(); + rXmlElement.AddElement(rXmlDataElementWrapper.Get(r_pair.first, GetWritingNDData(rWritingIndices, tensor_adaptor.pGetStorage()))); + } + } else { + std::visit([&](const auto p_variable) { + AddFieldsUsingTensorAdaptorImpl( + rXmlElement, pContainer, *p_variable, rXmlDataElementWrapper, + rDataCommunicator, rWritingIndices, EchoLevel, rArgs...); + }, r_pair.second); + } + } - return p_flag_expression; + KRATOS_CATCH(""); } -template -XmlExpressionElement::Pointer CreateFlagDataXmlElement( - const std::string& rFlagName, - const Flags& rFlags, - const ModelPart& rModelPart) -{ - if constexpr(std::is_same_v) { - const auto& r_communicator = rModelPart.GetCommunicator(); - const auto& r_local_nodes = r_communicator.LocalMesh().Nodes(); - const auto& r_ghost_nodes = r_communicator.GhostMesh().Nodes(); - - return CreateDataArrayElement( - rFlagName, - {&*CreateContainerFlagExpression(r_local_nodes, rFlags), - &*CreateContainerFlagExpression(r_ghost_nodes, rFlags)}); - } else if constexpr(std::is_same_v) { - return CreateDataArrayElement( - rFlagName, - {&*CreateContainerFlagExpression(rModelPart.GetCommunicator().LocalMesh().Conditions(), rFlags)}); - } else if constexpr(std::is_same_v) { - return CreateDataArrayElement( - rFlagName, - {&*CreateContainerFlagExpression(rModelPart.GetCommunicator().LocalMesh().Elements(), rFlags)}); - } -} - -Expression::Pointer CreateGhostNodeExpression( +template +void AddFields( + XmlElementsArray& rXmlElement, + const std::map& rMap, + TXmlDataElementWrapper& rXmlDataElementWrapper, + const std::vector& rWritingIndices, const DataCommunicator& rDataCommunicator, - const Expression& rLocalNodesExpression, - const ModelPart::NodesContainerType& rLocalNodes, - const ModelPart::NodesContainerType& rGhostNodes, - const std::unordered_map& rKratosVtuIndicesMap) + const IndexType EchoLevel) { - const IndexType number_of_ghost_nodes = rGhostNodes.size(); - - std::vector ghost_indices(number_of_ghost_nodes); - std::transform(rGhostNodes.begin(), rGhostNodes.end(), ghost_indices.begin(), [](const auto& rNode) { return rNode.Id(); }); - auto gp_list = GlobalPointerUtilities::RetrieveGlobalIndexedPointers(rLocalNodes, ghost_indices, rDataCommunicator); - - GlobalPointerCommunicator pointer_comm(rDataCommunicator, gp_list.ptr_begin(), gp_list.ptr_end()); + for (const auto& r_pair : rMap) { + KRATOS_INFO_IF("VtuOutput", EchoLevel > 2) << "------ Collecting " << r_pair.first << " data...\n"; + + std::visit([&rXmlElement, &r_pair, &rXmlDataElementWrapper, &rWritingIndices, &rDataCommunicator](auto pTensorAdaptor) { + // here we need to make sure all the tensor adaptors from every rank has the same data shape, even + // from the ranks which do not have any entities. Therefore following check is done with mpi communication + + // all the ranks should have the same number of dimensions, because number of dimensions should not depend + // on whether the rank is empty or not. + const auto& ta_shape = pTensorAdaptor->Shape(); + const auto max_number_of_dimensions = rDataCommunicator.MaxAll(static_cast(ta_shape.size())); + + KRATOS_ERROR_IF_NOT(max_number_of_dimensions == ta_shape.size()) + << "The number of dimensions represented by \"" << r_pair.first << "\" tensor adaptor is different in different ranks [ max number of dimensions from all ranks = " + << max_number_of_dimensions << ", tensor adaptor = " << *pTensorAdaptor << " ].\n"; + + // since all ranks have same number of dimensions, now we can check if the tensor adaptors have the correct sizes. + // in here we check the followings + // - each rank which does not have emtpy containers (ta_shape[0] != 0) should have same number of components in the data shape. + // - ranks which do have empty containers (ta_shape[0] == 0) should have either same number of components as in the ranks which have non empty + // containers or 0. + + std::vector communicated_shape(ta_shape.begin(), ta_shape.end()); + auto all_ta_shapes = rDataCommunicator.AllGatherv(communicated_shape); + + // find a data shape from some rank which has non-empty container + DenseVector ref_ta_shape(max_number_of_dimensions, 0); + for (const auto& rank_shape : all_ta_shapes) { + if (rank_shape[0] != 0) { + std::copy(rank_shape.begin() + 1, rank_shape.end(), ref_ta_shape.begin() + 1); + break; + } + } - const IndexType number_of_components = rLocalNodesExpression.GetItemComponentCount(); + for (IndexType i_rank = 0; i_rank < all_ta_shapes.size(); ++i_rank) { + auto& rank_shape = all_ta_shapes[i_rank]; + + // modify the rank shape if it is coming from a rank having an empty container. + if (rank_shape[0] == 0) { + // this is a rank with an empty container. + for (IndexType i_dim = 1; i_dim < ref_ta_shape.size(); ++i_dim) { + // modify only if the number of components in the higher dimensions are zero. + if (rank_shape[i_dim] == 0) { + rank_shape[i_dim] = ref_ta_shape[i_dim]; + } + } + } - auto values_proxy = pointer_comm.Apply( - [&rLocalNodesExpression, number_of_components, &rKratosVtuIndicesMap](GlobalPointer& rGP) -> std::vector { - std::vector values(number_of_components); - const auto p_itr = rKratosVtuIndicesMap.find(rGP->Id()); - if (p_itr != rKratosVtuIndicesMap.end()) { - const IndexType enitity_data_begin_index = p_itr->second * number_of_components; - for (IndexType i = 0; i < number_of_components; ++i) { - values[i] = rLocalNodesExpression.Evaluate(p_itr->second, enitity_data_begin_index, i); + // now we check in all ranks whether the data shape is equal + for (IndexType i_dim = 1; i_dim < ref_ta_shape.size(); ++i_dim) { + KRATOS_ERROR_IF_NOT(rank_shape[i_dim] == ref_ta_shape[i_dim]) + << "All ranks should have same number of components in the shape dimensions except for the first dimension. If the rank is empty," + << " then that rank should have zeros for all shape dimensions or correct number of components in the dimensions as in the ranks with" + << " non-empty containers [ mismatching shape rank = " << i_rank << ", mismatching tensor adaptor shape = " << rank_shape + << ", ref tensor adaptor shape from other ranks = " << ref_ta_shape << ", tensor adaptor name = " << r_pair.first + << ", tensor adaptor = " << *pTensorAdaptor << " ].\n"; } - } else { - KRATOS_ERROR << "The node with id " << rGP->Id() << " not found in the owning rank local expression."; } - return values; - } - ); - auto p_ghost_nodes_expression = LiteralFlatExpression::Create(number_of_ghost_nodes, rLocalNodesExpression.GetItemShape()); - auto data_itr = p_ghost_nodes_expression->begin(); + if (ta_shape[0] == 0) { + // get the storage type of the tensor adaptor. This may be NDData, NDData, ... + using TDataType = typename BareType::Storage; + // this is a rank with an empty container. + rXmlElement.AddElement(rXmlDataElementWrapper.Get(r_pair.first, Kratos::make_shared(ref_ta_shape))); + } else { + // this is a rank with non-empty container. + rXmlElement.AddElement(rXmlDataElementWrapper.Get(r_pair.first, GetWritingNDData(rWritingIndices, pTensorAdaptor->pGetStorage()))); + } - for(IndexType i = 0; i < number_of_ghost_nodes; ++i) { - const auto& r_gp_value = values_proxy.Get(gp_list(i)); - for (IndexType j = 0; j < number_of_components; ++j) { - *(data_itr++) = r_gp_value[j]; - } + }, r_pair.second); } - return p_ghost_nodes_expression; } -template -XmlExpressionElement::Pointer CreateContainerExpressionXmlElement( - const std::string& rExpressionName, - const ContainerExpression& rContainerExpression, - const std::unordered_map& rKratosVtuIndicesMap) -{ - if constexpr(std::is_same_v) { - const auto& r_communicator = rContainerExpression.GetModelPart().GetCommunicator(); - const auto& r_local_nodes = r_communicator.LocalMesh().Nodes(); - const auto& r_ghost_nodes = r_communicator.GhostMesh().Nodes(); - - auto ghost_node_expression = CreateGhostNodeExpression( - r_communicator.GetDataCommunicator(), rContainerExpression.GetExpression(), - r_local_nodes, r_ghost_nodes, rKratosVtuIndicesMap); - - return CreateDataArrayElement( - rExpressionName, {pGetExpression(rContainerExpression), &*ghost_node_expression}); - } else { - return CreateDataArrayElement(rExpressionName, - {pGetExpression(rContainerExpression)}); +template +ModelPart::NodesContainerType::Pointer GetNodesContainer(TEntityContainerType& rContainer) +{ + std::vector temp_nodes; + temp_nodes.reserve(rContainer.size() * 20); + for (auto& r_entity : rContainer) { + auto& r_geometry = r_entity.GetGeometry(); + for (auto p_itr = r_geometry.ptr_begin(); p_itr != r_geometry.ptr_end(); ++p_itr) { + temp_nodes.push_back(*p_itr); + } } -} -template -void CheckDataArrayName( - const std::string& rName, - TLists&... rLists) -{ - const bool found_existing_name = !(... && (rLists.find(rName) == rLists.end())); - KRATOS_ERROR_IF(found_existing_name) - << "Found an existing data array with the same name = \"" << rName << "\".\n"; + auto p_nodes_container = Kratos::make_shared(); + p_nodes_container->insert(temp_nodes.begin(), temp_nodes.end()); + return p_nodes_container; } -template -void AddListOfVariables( - XmlExpressionElement::Pointer pXmlDataElement, +void AddUnstructuredGridData( + std::vector& rOutput, ModelPart& rModelPart, - const std::map& rVariablesMap) + const IndexType EchoLevel, + const bool UseSubModelParts) { - for (const auto& p_variable_variant : rVariablesMap){ - std::visit([&rModelPart, &pXmlDataElement](auto pVariable) { - using variable_type = - typename std::remove_const_t>::Type; - AddDataArrayElement( - pXmlDataElement, - CreateVariableDataXmlElement( - *pVariable, rModelPart)); - }, - p_variable_variant.second); + const std::vector entity_availability{rModelPart.NumberOfNodes() > 0, rModelPart.NumberOfConditions() > 0, rModelPart.NumberOfElements() > 0}; + const auto& max_entity_availability = rModelPart.GetRootModelPart().GetCommunicator().GetDataCommunicator().MaxAll(entity_availability); + const bool has_nodes = max_entity_availability[0]; + const bool has_conditions = max_entity_availability[1]; + const bool has_elements = max_entity_availability[2]; + + if (has_elements) { + // Model part has elements. Hence add a separate output + // for elements. + + // now check if it has proper nodes + if (has_nodes) { + KRATOS_INFO_IF("VtuOutput", EchoLevel > 0) + << "Configuring output for \"" << rModelPart.FullName() << "\" elements with existing nodes container.\n"; + VtuOutput::UnstructuredGridData model_part_data{true, &rModelPart, rModelPart.pNodes(), rModelPart.pElements()}; + rOutput.push_back(model_part_data); + } else { + // create the nodes container. + KRATOS_INFO_IF("VtuOutput", EchoLevel > 0) + << "Configuring output for \"" << rModelPart.FullName() << "\" elements with new nodes container.\n"; + auto p_nodes = GetNodesContainer(rModelPart.Elements()); + VtuOutput::UnstructuredGridData model_part_data{false, &rModelPart, p_nodes, rModelPart.pElements()}; + rOutput.push_back(model_part_data); + } } -} -template -void AddListOfFlags( - XmlExpressionElement::Pointer pXmlDataElement, - ModelPart& rModelPart, - const std::map& rFlagsMap) -{ - for (const auto& r_flag_pair : rFlagsMap){ - AddDataArrayElement(pXmlDataElement, CreateFlagDataXmlElement(r_flag_pair.first, *r_flag_pair.second, rModelPart)); - } -} + if (has_conditions) { + // Model part has conditions. Hence add a separate output + // for conditions. -template -void AddListOfContainerExpressions( - XmlExpressionElement::Pointer pXmlDataElement, - ModelPart& rModelPart, - const std::unordered_map& rKratosVtuIndicesMap, - const std::map& rContainerExpressionsMap) -{ - for (const auto& r_container_expression_pair : rContainerExpressionsMap){ - const std::string& r_name = r_container_expression_pair.first; - if constexpr(std::is_same_v::Pointer>) { - AddDataArrayElement( - pXmlDataElement, - CreateContainerExpressionXmlElement( - r_name, - *r_container_expression_pair.second, rKratosVtuIndicesMap)); + if (!has_elements && has_nodes) { + KRATOS_INFO_IF("VtuOutput", EchoLevel > 0) + << "Configuring output for \"" << rModelPart.FullName() << "\" conditions with existing nodes container.\n"; + VtuOutput::UnstructuredGridData model_part_data{true, &rModelPart, rModelPart.pNodes(), rModelPart.pConditions()}; + rOutput.push_back(model_part_data); } else { - std::visit([&r_name, &pXmlDataElement, &rKratosVtuIndicesMap](auto pContainerExpression) { - AddDataArrayElement( - pXmlDataElement, - CreateContainerExpressionXmlElement( - r_name, *pContainerExpression, rKratosVtuIndicesMap)); - }, - r_container_expression_pair.second); + // either this model part also contains elements, or it does not + // contain nodes. In either case, the nodes list given by the rModelPart + // does not reflect the actual nodes used by the conditions. + // In order to avoid writing nodes, which are not used by the conditions, + // this will use a new nodes list. + + KRATOS_INFO_IF("VtuOutput", EchoLevel > 0) + << "Configuring output for \"" << rModelPart.FullName() << "\" conditions with new nodes container.\n"; + + auto p_nodes = GetNodesContainer(rModelPart.Conditions()); + VtuOutput::UnstructuredGridData model_part_data{false, &rModelPart, p_nodes, rModelPart.pConditions()}; + rOutput.push_back(model_part_data); } } -} -void CopyAttributes( - XmlExpressionElement& rOutputElement, - const XmlExpressionElement& rInputElement) -{ - for (const auto& r_attribute_data : rInputElement.GetAttributes()) { - rOutputElement.AddAttribute(r_attribute_data.first, r_attribute_data.second); + if (!has_elements && !has_conditions) { + KRATOS_INFO_IF("VtuOutput", EchoLevel > 0) + << "Configuring output for \"" << rModelPart.FullName() << "\" nodes.\n"; + // Model part does not have either conditions or elements. + // Hence, only adding the nodes. + VtuOutput::UnstructuredGridData model_part_data{true, &rModelPart, rModelPart.pNodes(), std::nullopt}; + rOutput.push_back(model_part_data); } -} -void CreatePDataArrays( - XmlExpressionElement& rOutputElement, - const XmlExpressionElement& rInputElement) -{ - for (const auto& p_element : rInputElement.GetElements()) { - auto new_pdata_array = Kratos::make_shared("PDataArray"); - CopyAttributes(*new_pdata_array, *p_element); - rOutputElement.AddElement(new_pdata_array); + if (UseSubModelParts) { + // now recursively add all the sub model part data. + for (auto& r_sub_model_part : rModelPart.SubModelParts()) { + AddUnstructuredGridData(rOutput, r_sub_model_part, EchoLevel, UseSubModelParts); + } } } -std::string GetEndianness() +template +const typename VtuOutput::DataList::value_type& GetContainerMap( + const VtuOutput::DataList& rList, + TCellPointerType pCellPointer) { - int i = 0x0001; - - if (*reinterpret_cast(&i) != 0) { - return "LittleEndian"; - } else { - return "BigEndian"; - } + return std::visit([&rList](auto pContainer) -> const typename VtuOutput::DataList::value_type& { + using container_type = BareType; + if constexpr(std::is_same_v) { + return rList[static_cast(Globals::DataLocation::Condition)]; + } else if constexpr(std::is_same_v) { + return rList[static_cast(Globals::DataLocation::Element)]; + } else { + KRATOS_ERROR << "Unsupported container type."; + return rList[static_cast(Globals::DataLocation::Element)]; + } + }, pCellPointer); } -void WritePvtuFile( - XmlExpressionElement::Pointer pVtkFileElement, - const ModelPart& rModelPart, - const std::string& rOutputFileNamePrefix, - const std::string& rOutputFileName) +std::string WritePartitionedUnstructuredGridData( + XmlElementsArray& rPointDataElement, + XmlElementsArray& rCellDataElement, + const std::string& rOutputVtuFileName, + const DataCommunicator& rDataCommunicator) { - // get list of file names - std::stringstream list_of_file_names; + const int writing_rank = 0; - const auto& r_communicator = rModelPart.GetCommunicator(); - const auto& r_data_communicator = r_communicator.GetDataCommunicator(); + // remove the rank from the rOutputVtuFileName. + const auto& r_base_name = rOutputVtuFileName.substr(0, rOutputVtuFileName.rfind("_")); - // TODO: May be we want to check a rank which has some entities (not empty ranks) - // Then write on that rank. - const int writing_rank = 0; + const auto& p_vtu_file_name = r_base_name + ".pvtu"; - list_of_file_names << rOutputFileName << "\n"; - if (r_data_communicator.Rank() == writing_rank) { - for (int rank = 0; rank < r_data_communicator.Size(); ++rank) { - if (rank != writing_rank) { - std::string msg; - r_data_communicator.Recv(msg, rank); - list_of_file_names << msg; - } + if (rDataCommunicator.Rank() == writing_rank) { + // create the pvtu file + XmlElementsArray p_vtu_file_element("VTKFile"); + p_vtu_file_element.AddAttribute("type", "PUnstructuredGrid"); + p_vtu_file_element.AddAttribute("version", "0.1"); + p_vtu_file_element.AddAttribute("byte_order", GetEndianness()); + + // create the unstructured grid + auto p_unstructured_grid_element = Kratos::make_shared("PUnstructuredGrid"); + p_unstructured_grid_element->AddAttribute("GhostLevel", "0"); + p_vtu_file_element.AddElement(p_unstructured_grid_element); + + // ppoints_element + auto p_points_element = Kratos::make_shared("PPoints"); + p_unstructured_grid_element->AddElement(p_points_element); + + // position element + auto p_position_element = Kratos::make_shared("PDataArray"); + p_position_element->AddAttribute("type", "Float64"); + p_position_element->AddAttribute("Name", "Position"); + p_position_element->AddAttribute("NumberOfComponents", "3"); + p_points_element->AddElement(p_position_element); + + // pcells element + auto p_cells_element = Kratos::make_shared("PCells"); + p_unstructured_grid_element->AddElement(p_cells_element); + + // connectivity element + auto p_connectivity_element = Kratos::make_shared("PDataArray"); + p_connectivity_element->AddAttribute("type", "Int32"); + p_connectivity_element->AddAttribute("Name", "connectivity"); + p_connectivity_element->AddAttribute("NumberOfComponents", "1"); + p_cells_element->AddElement(p_connectivity_element); + + // offsets element + auto p_offsets_element = Kratos::make_shared("PDataArray"); + p_offsets_element->AddAttribute("type", "Int32"); + p_offsets_element->AddAttribute("Name", "offsets"); + p_offsets_element->AddAttribute("NumberOfComponents", "1"); + p_cells_element->AddElement(p_offsets_element); + + // types element + auto p_types_element = Kratos::make_shared("PDataArray"); + p_types_element->AddAttribute("type", "UInt8"); + p_types_element->AddAttribute("Name", "types"); + p_types_element->AddAttribute("NumberOfComponents", "1"); + p_cells_element->AddElement(p_types_element); + + // ppoint data element + auto p_point_data_element = Kratos::make_shared("PPointData"); + p_unstructured_grid_element->AddElement(p_point_data_element); + + // now add the point data fields + for (const auto& p_element : rPointDataElement.GetElements()) { + auto p_current_element = Kratos::make_shared("PDataArray"); + CopyAttributes(*p_element, *p_current_element); + p_point_data_element->AddElement(p_current_element); } - } else { - r_data_communicator.Send(list_of_file_names.str(), writing_rank); - } - r_data_communicator.Barrier(); - if (r_data_communicator.Rank() == writing_rank) { - // create the vtk file - auto vtk_file_element = Kratos::make_shared("VTKFile"); - vtk_file_element->AddAttribute("type", "PUnstructuredGrid"); - vtk_file_element->AddAttribute("version", "0.1"); - vtk_file_element->AddAttribute("byte_order", GetEndianness()); + // pcell data element + auto p_cell_data_element = Kratos::make_shared("PCellData"); + p_unstructured_grid_element->AddElement(p_cell_data_element); - // create the unstructured grid - auto unstructured_grid_element = Kratos::make_shared("PUnstructuredGrid"); - unstructured_grid_element->AddAttribute("GhostLevel", "0"); - vtk_file_element->AddElement(unstructured_grid_element); - - // get the points xml element - auto piece = pVtkFileElement->GetElements("UnstructuredGrid")[0]->GetElements("Piece")[0]; - - auto points = piece->GetElements("Points")[0]; - auto p_points = Kratos::make_shared("PPoints"); - VtuOutputHelperUtilities::CreatePDataArrays(*p_points, *points); - unstructured_grid_element->AddElement(p_points); - - auto cells = piece->GetElements("Cells")[0]; - auto p_cells = Kratos::make_shared("PCells"); - VtuOutputHelperUtilities::CreatePDataArrays(*p_cells, *cells); - unstructured_grid_element->AddElement(p_cells); - - auto point_data = piece->GetElements("PointData")[0]; - auto p_point_data = Kratos::make_shared("PPointData"); - VtuOutputHelperUtilities::CreatePDataArrays(*p_point_data, *point_data); - unstructured_grid_element->AddElement(p_point_data); - - auto cell_data = piece->GetElements("CellData")[0]; - auto p_cell_data = Kratos::make_shared("PCellData"); - VtuOutputHelperUtilities::CreatePDataArrays(*p_cell_data, *cell_data); - unstructured_grid_element->AddElement(p_cell_data); - - // now write all the pieces - const auto& r_file_names = StringUtilities::SplitStringByDelimiter(list_of_file_names.str(), '\n'); - for (const auto& r_file_name : r_file_names) { - auto piece = Kratos::make_shared("Piece"); - piece->AddAttribute("Source", r_file_name); - unstructured_grid_element->AddElement(piece); + // now add the cell data fields + for (const auto& p_element : rCellDataElement.GetElements()) { + auto p_current_element = Kratos::make_shared("PDataArray"); + CopyAttributes(*p_element, *p_current_element); + p_cell_data_element->AddElement(p_current_element); + } + + // now add the piece elements + for (int i_rank = 0; i_rank < rDataCommunicator.Size(); ++i_rank) { + const auto& r_file_name = r_base_name + "_" + std::to_string(i_rank) + ".vtu"; + auto piece = Kratos::make_shared("Piece"); + // since we are writing to the same folder the pvtu files + piece->AddAttribute( + "Source", std::filesystem::relative( + std::filesystem::absolute(r_file_name), + std::filesystem::absolute(p_vtu_file_name).parent_path()) + .generic_string()); + p_unstructured_grid_element->AddElement(piece); } // writing to file - std::stringstream output_pvtu_file_name; - output_pvtu_file_name << rOutputFileNamePrefix << ".pvtu"; std::ofstream output_file; - output_file.open(output_pvtu_file_name.str(), std::ios::out | std::ios::trunc); - XmlOStreamAsciiWriter writer(output_file, 1); - writer.WriteElement(*vtk_file_element); - output_file.close(); + output_file.open(p_vtu_file_name, std::ios::out | std::ios::trunc); + output_file << "\n"; + p_vtu_file_element.Write(output_file); + + } + + return p_vtu_file_name; +} + +template +void PrintDataLocationData( + std::ostream& rOStream, + const std::string& rMapType, + const VtuOutput::DataList& rList) +{ + rOStream << "List of " << rMapType << "s:"; + for (IndexType i = 0; i < rList.size(); ++i) { + switch (i) { + case static_cast(Globals::DataLocation::NodeHistorical): + rOStream << "\n\tNode historical " << rMapType << "s:"; + break; + case static_cast(Globals::DataLocation::NodeNonHistorical): + rOStream << "\n\tNode " << rMapType << "s:"; + break; + case static_cast(Globals::DataLocation::Condition): + rOStream << "\n\tCondition " << rMapType << "s:"; + break; + case static_cast(Globals::DataLocation::Element): + rOStream << "\n\tElement " << rMapType << "s:"; + break; + default: + break; + } + + for ([[maybe_unused]]const auto& [name, variable] : rList[i]) { + rOStream << "\n\t\t" << name; + } } } -}; // namespace VtuOutputHelperUtilities +template +std::pair::iterator> FindUnstructuredGridData( + const TContainerType& rContainer, + std::vector& rUnstructuredGridDataList) +{ + for (auto itr = rUnstructuredGridDataList.begin(); itr != rUnstructuredGridDataList.end(); ++itr) { + auto p_model_part = itr->mpModelPart; + if constexpr(std::is_same_v) { + if (itr->UsePointsForDataFieldOutput) { + if ( + &rContainer == &p_model_part->Nodes() || + (!p_model_part->IsDistributed() && &rContainer == &p_model_part->GetCommunicator().LocalMesh().Nodes()) + ) { + return std::make_pair(Globals::DataLocation::NodeNonHistorical, itr); + } + } + } else if constexpr(std::is_same_v) { + // since Kratos is doing partitioning based on elements, and there are no conditions + // on the ghost meshes. so normal mesh and the local mesh should be having identical entities. + if (itr->mpCells.has_value() && + std::holds_alternative(itr->mpCells.value()) && + ( + &rContainer == &*std::get(itr->mpCells.value()) || + &rContainer == &p_model_part->GetCommunicator().LocalMesh().Conditions() + ) + ) { + return std::make_pair(Globals::DataLocation::Condition, itr); + } + } else if constexpr(std::is_same_v) { + // since Kratos is doing partitioning based on elements, and there are no elements + // on the ghost meshes. so normal mesh and the local mesh should be having identical entities. + if (itr->mpCells.has_value() && + std::holds_alternative(itr->mpCells.value()) && + ( + &rContainer == &*std::get(itr->mpCells.value()) || + &rContainer == &p_model_part->GetCommunicator().LocalMesh().Elements() + ) + ) { + return std::make_pair(Globals::DataLocation::Element, itr); + } + } else { + KRATOS_ERROR << "Unsupported container type."; + } + } + + return std::make_pair(Globals::DataLocation::ModelPart, rUnstructuredGridDataList.end()); +} + +} // namespace VtuOutput::VtuOutput( ModelPart& rModelPart, - const bool IsInitialConfiguration, + const Globals::Configuration Configuration, const WriterFormat OutputFormat, - const IndexType Precision) - : mrModelPart(rModelPart), - mIsInitialConfiguration(IsInitialConfiguration), + const IndexType Precision, + const bool OutputSubModelParts, + const bool WriteIds, + const IndexType EchoLevel) + : mIsPVDFileHeaderWritten(false), + mrModelPart(rModelPart), + mConfiguration(Configuration), + mEchoLevel(EchoLevel), mOutputFormat(OutputFormat), mPrecision(Precision) { - const auto& r_communicator = rModelPart.GetCommunicator(); + AddUnstructuredGridData(mUnstructuredGridDataList, rModelPart, mEchoLevel, OutputSubModelParts); + + // sort the order of output to be consistent between different compilers + std::sort(mUnstructuredGridDataList.begin(), mUnstructuredGridDataList.end(), + [](const auto& rV1, const auto& rV2) { + return rV1.mpModelPart->FullName() < rV2.mpModelPart->FullName(); + }); + + if (WriteIds) { + // Adds a dummy place holder called "KRATOS_ID" to every container type + // so the user is prohibited from adding any tensor adaptors + // with the name KRATOS_ID in future. This will be treated + // separately, hence the use of nullptr. + mFlags[static_cast(Globals::DataLocation::NodeNonHistorical)]["KRATOS_ID"] = nullptr; + mFlags[static_cast(Globals::DataLocation::Condition)]["KRATOS_ID"] = nullptr; + mFlags[static_cast(Globals::DataLocation::Element)]["KRATOS_ID"] = nullptr; + } +} - mIsConditionsConsidered = r_communicator.GlobalNumberOfConditions() > 0; - mIsElementsConsidered = r_communicator.GlobalNumberOfElements() > 0; +const ModelPart& VtuOutput::GetModelPart() const +{ + return mrModelPart; +} - KRATOS_WARNING_IF("VtuOutput", mIsElementsConsidered && mIsConditionsConsidered) - << "Conditions and Elements vtu output chosen for " << mrModelPart.FullName() - << " which is not supported. Giving priority to elements.\n"; +std::vector VtuOutput::GetOutputContainerList() const +{ + std::vector result; + for (const auto& r_unstructured_grid : mUnstructuredGridDataList) { + if (r_unstructured_grid.UsePointsForDataFieldOutput) { + result.push_back(r_unstructured_grid.mpPoints); + + if (!r_unstructured_grid.mpModelPart->GetRootModelPart().IsDistributed()) { + // since local mesh and the mesh are the same in the case of non-distributed + // run. + result.push_back(r_unstructured_grid.mpModelPart->GetCommunicator().LocalMesh().pNodes()); + } + } - mIsConditionsConsidered = mIsElementsConsidered ? false : mIsConditionsConsidered; + if (r_unstructured_grid.mpCells.has_value()) { + std::visit([&result, &r_unstructured_grid](auto p_cells) { + result.push_back(p_cells); - if (mIsConditionsConsidered || mIsElementsConsidered) { - // we first always use the local mesh - IndexType vtu_index = 0; - for (const auto& r_node : mrModelPart.GetCommunicator().LocalMesh().Nodes()) { - mKratosVtuIndicesMap[r_node.Id()] = vtu_index++; + // since local mesh and the mesh are the same. + using container_type = BareType; + if constexpr(std::is_same_v) { + result.push_back(r_unstructured_grid.mpModelPart->GetCommunicator().LocalMesh().pConditions()); + } else if constexpr(std::is_same_v) { + result.push_back(r_unstructured_grid.mpModelPart->GetCommunicator().LocalMesh().pElements()); + } + }, r_unstructured_grid.mpCells.value()); } + } + return result; +} - // then we add the ghost mesh - for (const auto& r_node : mrModelPart.GetCommunicator().GhostMesh().Nodes()) { - mKratosVtuIndicesMap[r_node.Id()] = vtu_index++; - } +void VtuOutput::AddFlag( + const std::string& rFlagName, + const Flags& rFlagVariable, + const Globals::DataLocation& DataLocation) +{ + KRATOS_TRY + + KRATOS_ERROR_IF(mIsPVDFileHeaderWritten) + << "Flags can be added only before the first call to the PrintOutput [ flag name = " + << rFlagName << " ].\n"; + + switch (DataLocation) { + case Globals::DataLocation::NodeNonHistorical: + // user is trying to add a flag to nodes. now we are checking + // whether there are variables with the same name in the variables + // from the nodal historical. + // note: there is no break here. + CheckDataArrayName(rFlagName, Globals::DataLocation::NodeHistorical, mFlags); + CheckDataArrayName(rFlagName, Globals::DataLocation::NodeHistorical, mVariables); + case Globals::DataLocation::Condition: + case Globals::DataLocation::Element: + // The following code block will be executed for Globals::DataLocation::NodeHistorical, Globals::DataLocation::Condition, and Globals::DataLocation::Element. + + // user is trying to add a flag variable to nodes, conditions or elements. + // here we check if the given flag name is there in the existing flags for user specified data location, + // and also in the variables. + CheckDataArrayName(rFlagName, DataLocation, mFlags); + CheckDataArrayName(rFlagName, DataLocation, mVariables); + + // since specified flags are used to output in every unstructured grid. We check here whether + // any of the tensor adaptors in the given data location contains the same name as rFlagName. + CheckDataArrayName(rFlagName, DataLocation, mUnstructuredGridDataList); + + // If there are no conflicts, we add the flag variable. + mFlags[static_cast(DataLocation)][rFlagName] = &rFlagVariable; + break; + default: + KRATOS_ERROR << "Flags can be only added to NodeNonHistorical, Condition, and Element data locations."; + break; } + + KRATOS_CATCH(""); } template -void VtuOutput::AddHistoricalVariable(const Variable& rVariable) +void VtuOutput::AddVariable( + const Variable& rVariable, + const Globals::DataLocation& DataLocation) { - VtuOutputHelperUtilities::CheckDataArrayName( - rVariable.Name(), mNonHistoricalNodalVariablesMap, mNodalFlagsMap, mPointContainerExpressionsMap); - mHistoricalVariablesMap[rVariable.Name()] = &rVariable; + KRATOS_TRY + + KRATOS_ERROR_IF(mIsPVDFileHeaderWritten) + << "Variables can be added only before the first call to the PrintOutput [ variable name = " + << rVariable.Name() << " ].\n"; + + switch (DataLocation) { + case Globals::DataLocation::NodeHistorical: + // Now the user is adding a nodal historical variable. So, this checks whether + // the a variable with the same name exists in the nodal non-historical variables map. + // note: there is no break in here. + CheckDataArrayName(rVariable.Name(), Globals::DataLocation::NodeNonHistorical, mFlags); + CheckDataArrayName(rVariable.Name(), Globals::DataLocation::NodeNonHistorical, mVariables); + case Globals::DataLocation::NodeNonHistorical: + // Now the user is adding a nodal non-historical variable. So this checks whether + // a variable with the same name exists in the nodal historical variables map. + // not: there is no break in here. + CheckDataArrayName(rVariable.Name(), Globals::DataLocation::NodeHistorical, mFlags); + CheckDataArrayName(rVariable.Name(), Globals::DataLocation::NodeHistorical, mVariables); + case Globals::DataLocation::Condition: + case Globals::DataLocation::Element: + // The following code block will be executed for Globals::DataLocation::NodeHistorical, Globals::DataLocation::NodeNonHistorical, Globals::DataLocation::Condition, and Globals::DataLocation::Element. + + // Now the user is trying to add a nodal-historical, nodal-non-historical, element or condition variable. + // so now we check whether another variable with the same name exists + // in the user specified container in flags and variables maps. + CheckDataArrayName(rVariable.Name(), DataLocation, mFlags); + CheckDataArrayName(rVariable.Name(), DataLocation, mVariables); + + // this checks whether there is already a tensor adaptor added with a name equal to the variable name + // in any of the unstructured grids. Since these variables will be used to output data in all the unstructured grids, + // non-of them should have any tensor adaptors with this name. + CheckDataArrayName(rVariable.Name(), DataLocation, mUnstructuredGridDataList); // checks in the tensor adaptors list + + // if there are no conflicts, adding the variable. + mVariables[static_cast(DataLocation)][rVariable.Name()] = &rVariable; + break; + default: + KRATOS_ERROR << "Variables can be only added to NodeHistorical, NodeNonHistorical, Condition, and Element data locations."; + break; + } + + KRATOS_CATCH(""); } template -void VtuOutput::AddNonHistoricalVariable( +void VtuOutput::AddIntegrationPointVariable( const Variable& rVariable, - const Flags& rEntityFlags) + const Globals::DataLocation& DataLocation) { - if (rEntityFlags.Is(NODES)) { - VtuOutputHelperUtilities::CheckDataArrayName( - rVariable.Name(), mHistoricalVariablesMap, mNodalFlagsMap, - mPointContainerExpressionsMap); - mNonHistoricalNodalVariablesMap[rVariable.Name()] = &rVariable; - } else { - KRATOS_ERROR_IF_NOT(!rEntityFlags.Is(CONDITIONS) || (rEntityFlags.Is(CONDITIONS) && mIsConditionsConsidered)) - << "Condition variable \"" - << rVariable.Name() << "\" cannot be written for a model part with elements [ model part name = \"" - << mrModelPart.FullName() << "\" ].\n"; + KRATOS_TRY + + KRATOS_ERROR_IF(mIsPVDFileHeaderWritten) + << "Integration point variables can be added only before the first call to the PrintOutput [ integration point variable name = " + << rVariable.Name() << " ].\n"; + + switch (DataLocation) { + case Globals::DataLocation::Condition: + case Globals::DataLocation::Element: + // The following code block will be executed for Globals::DataLocation::Condition and Globals::DataLocation::Element. + + // checks if the integration point variable name already exists on the + // list of integration point variables. + CheckDataArrayName(rVariable.Name(), DataLocation, mIntegrationPointVariables); + + // If no conflicts in the naming is found, then put integration point variable for the output. + mIntegrationPointVariables[static_cast(DataLocation)][rVariable.Name()] = &rVariable; + break; + default: + KRATOS_ERROR << "Integration point variables can be only added to Condition, and Element data locations."; + break; + } - KRATOS_ERROR_IF_NOT(!rEntityFlags.Is(ELEMENTS) || (rEntityFlags.Is(ELEMENTS) && mIsElementsConsidered)) - << "Element variable \"" - << rVariable.Name() << "\" cannot be written for a model part with only conditions [ model part name = \"" - << mrModelPart.FullName() << "\" ].\n"; + KRATOS_CATCH(""); +} - VtuOutputHelperUtilities::CheckDataArrayName( - rVariable.Name(), mCellFlagsMap, mCellContainerExpressionsMap); - mNonHistoricalCellVariablesMap[rVariable.Name()] = &rVariable; - } +template +void VtuOutput::AddTensorAdaptor( + const std::string& rTensorAdaptorName, + TTensorAdaptorPointerType pTensorAdaptor) +{ + KRATOS_TRY + + KRATOS_ERROR_IF(mIsPVDFileHeaderWritten) + << "TensorAdaptors can be added only before the first call to the PrintOutput [ tensor adaptor name = " + << rTensorAdaptorName << " ].\n"; + + // a visitor for NodesContainer::Pointer, ConditionsContainer::Pointer, ElementsContainerPointer + // of the given pTensorAdaptor + std::visit([this, &rTensorAdaptorName, &pTensorAdaptor](auto pContainer){ + // finds the unstructured grid for which the given tensor adaptor's pContainer refers to. + // mesh_type is of Kratos::Globals::DataLocation enum + // itr points to the unstructured grid which is referring to the given pContainer. + // if not found, mesh_type is returned with Kratos::Globals::DataLocation::ModelPart + // enum value, which will throw an error. + [[maybe_unused]] auto [mesh_type, itr] = FindUnstructuredGridData(*pContainer, this->mUnstructuredGridDataList); + + switch (mesh_type) { + case Globals::DataLocation::Condition: + case Globals::DataLocation::Element: { + // The following code block will be executed for Globals::DataLocation::Condition and Globals::DataLocation::Element. + + // here we have to check if the specified tensor adaptor name is there in the found unstructured grid + // referred by the itr. + + // checks in the condition or element maps of flags and variables whether the rTensorAdaptorName already + // exists. + CheckDataArrayName(rTensorAdaptorName, mesh_type, mFlags); // checks in the current data location of mFlags map + CheckDataArrayName(rTensorAdaptorName, mesh_type, mVariables); // checks in the current data location of mVariables map + + // checks in either Condition or Element map of tensor adaptors whether the given rTensorAdaptorName + // exists + CheckDataArrayName(rTensorAdaptorName, mesh_type, *itr); + + // If no conflicts in the naming is found, then put the tensor adaptor for output. + itr->mMapOfCellTensorAdaptors[rTensorAdaptorName] = pTensorAdaptor; + break; + } + case Globals::DataLocation::NodeNonHistorical: { + // checks if the given rTensorAdaptorName is already there in the nodal non-historical + // variables list, nodal-non-historical variables list and flags list. + CheckDataArrayName(rTensorAdaptorName, Globals::DataLocation::NodeNonHistorical, mFlags); + CheckDataArrayName(rTensorAdaptorName, Globals::DataLocation::NodeNonHistorical, mVariables); + CheckDataArrayName(rTensorAdaptorName, Globals::DataLocation::NodeHistorical, mFlags); + CheckDataArrayName(rTensorAdaptorName, Globals::DataLocation::NodeHistorical, mVariables); + + // checks if the given rTensorAdaptorName is already there in the list of nodal tensor adaptors + // of the unstructured grid referred by itr. + CheckDataArrayName(rTensorAdaptorName, Globals::DataLocation::NodeNonHistorical, *itr); + + // If no conflicts in the naming is found, then put the tensor adaptor for output. + itr->mMapOfPointTensorAdaptors[rTensorAdaptorName] = pTensorAdaptor; + break; + } + default: + KRATOS_ERROR + << "The container in the TensorAdaptor is not referring to any of the containers " + << "written by this Vtu output [ tensor adaptor name = " << rTensorAdaptorName + << ", tensor_adaptor = " << *pTensorAdaptor << " ]\n" + << *this; + break; + } + }, pTensorAdaptor->GetContainer()); + + KRATOS_CATCH(""); } -void VtuOutput::AddFlagVariable( - const std::string& rFlagName, - const Flags& rFlagVariable, - const Flags& rEntityFlags) +template +void VtuOutput::ReplaceTensorAdaptor( + const std::string& rTensorAdaptorName, + TTensorAdaptorPointerType pTensorAdaptor) { - if (rEntityFlags.Is(NODES)) { - VtuOutputHelperUtilities::CheckDataArrayName( - rFlagName, mHistoricalVariablesMap, mNonHistoricalNodalVariablesMap, - mPointContainerExpressionsMap); - mNodalFlagsMap[rFlagName] = &rFlagVariable; - } else { - KRATOS_ERROR_IF_NOT(!rEntityFlags.Is(CONDITIONS) || (rEntityFlags.Is(CONDITIONS) && mIsConditionsConsidered)) - << "Condition flag \"" - << rFlagName << "\" cannot be written for a model part with elements [ model part name = \"" - << mrModelPart.FullName() << "\" ].\n"; + KRATOS_TRY + + // a visitor for NodesContainer::Pointer, ConditionsContainer::Pointer, ElementsContainerPointer + // of the given pTensorAdaptor + std::visit([this, &rTensorAdaptorName, &pTensorAdaptor](auto pContainer){ + // finds the unstructured grid for which the given tensor adaptor's pContainer refers to. + // mesh_type is of Kratos::Globals::DataLocation enum + // itr points to the unstructured grid which is referring to the given pContainer. + // if not found, mesh_type is returned with Kratos::Globals::DataLocation::ModelPart + // enum value, which will throw an error. + [[maybe_unused]] auto [mesh_type, itr] = FindUnstructuredGridData(*pContainer, this->mUnstructuredGridDataList); + + switch (mesh_type) { + case Globals::DataLocation::Condition: + case Globals::DataLocation::Element: { + // The following code block will be executed for Globals::DataLocation::Condition and Globals::DataLocation::Element. + auto data_field_itr = itr->mMapOfCellTensorAdaptors.find(rTensorAdaptorName); + + KRATOS_ERROR_IF(data_field_itr == itr->mMapOfCellTensorAdaptors.end()) + << "TensorAdaptor name = \"" + << rTensorAdaptorName << "\" not found in the existing data fields. It is only allowed to update existing data fields. VtuOutput: \n" + << *this; + + data_field_itr->second = pTensorAdaptor; + break; + } + case Globals::DataLocation::NodeNonHistorical: { + auto data_field_itr = itr->mMapOfPointTensorAdaptors.find(rTensorAdaptorName); - KRATOS_ERROR_IF_NOT(!rEntityFlags.Is(ELEMENTS) || (rEntityFlags.Is(ELEMENTS) && mIsElementsConsidered)) - << "Element flag \"" - << rFlagName << "\" cannot be written for a model part with only conditions [ model part name = \"" - << mrModelPart.FullName() << "\" ].\n"; + KRATOS_ERROR_IF(data_field_itr == itr->mMapOfPointTensorAdaptors.end()) + << "TensorAdaptor name = \"" + << rTensorAdaptorName << "\" not found in the existing data fields. It is only allowed to update existing data fields. VtuOutput: \n" + << *this; - VtuOutputHelperUtilities::CheckDataArrayName( - rFlagName, mNonHistoricalCellVariablesMap, mCellContainerExpressionsMap); - mCellFlagsMap[rFlagName] = &rFlagVariable; - } + data_field_itr->second = pTensorAdaptor; + break; + } + default: + KRATOS_ERROR + << "The container in the TensorAdaptor is not referring to any of the containers " + << "written by this Vtu output [ tensor adaptor name = " << rTensorAdaptorName + << ", tensor_adaptor = " << *pTensorAdaptor << " ]\n" + << *this; + break; + } + }, pTensorAdaptor->GetContainer()); + + KRATOS_CATCH(""); } -template -void VtuOutput::AddContainerExpression( - const std::string& rExpressionName, - const typename ContainerExpression::Pointer pContainerExpression) -{ - if constexpr(std::is_same_v) { - KRATOS_ERROR_IF_NOT(mIsConditionsConsidered) - << "Conditions container expression \"" << rExpressionName - << "\" cannot be written for a model part with elements [ model part name = \"" - << mrModelPart.FullName() << "\" ].\n"; - } else if constexpr(std::is_same_v) { - KRATOS_ERROR_IF_NOT(mIsElementsConsidered) - << "Elements container expression \"" << rExpressionName - << "\" cannot be written for a model part with only conditions [ model part name = \"" - << mrModelPart.FullName() << "\" ].\n"; - } - - KRATOS_ERROR_IF_NOT(&pContainerExpression->GetModelPart() == &mrModelPart) - << "Model part mismatch in container expression addition. [ Vtu output model part name = \"" - << mrModelPart.FullName() << "\", container expression model part name = \"" - << pContainerExpression->GetModelPart().FullName() << "\" ].\n"; - - if constexpr (std::is_same_v) { - VtuOutputHelperUtilities::CheckDataArrayName( - rExpressionName, mHistoricalVariablesMap, - mNonHistoricalNodalVariablesMap, mNodalFlagsMap); - mPointContainerExpressionsMap[rExpressionName] = pContainerExpression; +template +void VtuOutput::EmplaceTensorAdaptor( + const std::string& rTensorAdaptorName, + TTensorAdaptorPointerType pTensorAdaptor) +{ + if (!mIsPVDFileHeaderWritten) { + AddTensorAdaptor(rTensorAdaptorName, pTensorAdaptor); } else { - VtuOutputHelperUtilities::CheckDataArrayName( - rExpressionName, mNonHistoricalCellVariablesMap, mCellFlagsMap); - mCellContainerExpressionsMap[rExpressionName] = pContainerExpression; + ReplaceTensorAdaptor(rTensorAdaptorName, pTensorAdaptor); } } -void VtuOutput::PrintModelPart( +template +std::pair VtuOutput::WriteUnstructuredGridData( + TXmlElementDataWrapperCreateFunctor&& rElementDataWrapperCreateFunctor, + TXmlElementDataWrapperAppendFunctor&& rElementDataWrapperAppendFunctor, + UnstructuredGridData& rUnstructuredGridData, const std::string& rOutputFileNamePrefix, - ModelPart& rModelPart) const + const IndexType Step) const { + const auto& r_data_communicator = mrModelPart.GetCommunicator().GetDataCommunicator(); + auto p_nodes = rUnstructuredGridData.mpPoints; + // create the vtk file - auto vtk_file_element = Kratos::make_shared("VTKFile"); - vtk_file_element->AddAttribute("type", "UnstructuredGrid"); - vtk_file_element->AddAttribute("version", "0.1"); - vtk_file_element->AddAttribute("byte_order", VtuOutputHelperUtilities::GetEndianness()); + XmlElementsArray vtk_file_element("VTKFile"); + vtk_file_element.AddAttribute("type", "UnstructuredGrid"); + vtk_file_element.AddAttribute("version", "0.1"); + vtk_file_element.AddAttribute("byte_order", GetEndianness()); // create the unstructured grid - auto unstructured_grid_element = Kratos::make_shared("UnstructuredGrid"); - vtk_file_element->AddElement(unstructured_grid_element); + auto unstructured_grid_element = Kratos::make_shared("UnstructuredGrid"); + vtk_file_element.AddElement(unstructured_grid_element); + + auto p_xml_data_element_wrapper = rElementDataWrapperCreateFunctor(); + rElementDataWrapperAppendFunctor(vtk_file_element, p_xml_data_element_wrapper); // create the piece element - auto piece_element = Kratos::make_shared("Piece"); - piece_element->AddAttribute("NumberOfPoints", - std::to_string(rModelPart.NumberOfNodes())); - piece_element->AddAttribute( - "NumberOfCells", - std::to_string(mIsElementsConsidered ? rModelPart.NumberOfElements() - : rModelPart.NumberOfConditions())); + auto piece_element = Kratos::make_shared("Piece"); + // adding number of points + piece_element->AddAttribute("NumberOfPoints", std::to_string(p_nodes->size())); unstructured_grid_element->AddElement(piece_element); + // create the position element + KRATOS_INFO_IF("VtuOutput", mEchoLevel > 2) << "--- Collecting nodal " << (mConfiguration == Globals::Configuration::Initial ? "initial" : "current") << " position data...\n"; + NodePositionTensorAdaptor node_position_tensor_adaptor(p_nodes, mConfiguration); + node_position_tensor_adaptor.CollectData(); + // create the points element - auto points_element = VtuOutputHelperUtilities::CreatePointsXmlElement( - rModelPart, mIsInitialConfiguration); + auto points_element = Kratos::make_shared("Points"); + points_element->AddElement(p_xml_data_element_wrapper->Get("Position", node_position_tensor_adaptor.pGetStorage())); piece_element->AddElement(points_element); // create the cells element - XmlExpressionElement::Pointer cells_element; - if (mIsElementsConsidered) { - cells_element = VtuOutputHelperUtilities::CreateCellsXmlElement( - rModelPart.GetCommunicator().LocalMesh().Elements(), mKratosVtuIndicesMap); - } else { - cells_element = VtuOutputHelperUtilities::CreateCellsXmlElement( - rModelPart.GetCommunicator().LocalMesh().Conditions(), mKratosVtuIndicesMap); + auto cells_element = Kratos::make_shared("Cells"); + std::vector writing_indices; + if (rUnstructuredGridData.mpCells.has_value()) { + KRATOS_INFO_IF("VtuOutput", mEchoLevel > 2) << "--- Collecting " << GetEntityName(rUnstructuredGridData.mpCells) << " connectivity data...\n"; + AddConnectivityData(*cells_element, writing_indices, *rUnstructuredGridData.mpPoints, rUnstructuredGridData.mpCells.value(), *p_xml_data_element_wrapper, mEchoLevel); } + piece_element->AddAttribute("NumberOfCells", std::to_string(writing_indices.size())); piece_element->AddElement(cells_element); // create the point data - auto point_data_element = Kratos::make_shared("PointData"); + auto point_data_element = Kratos::make_shared("PointData"); piece_element->AddElement(point_data_element); - VtuOutputHelperUtilities::AddListOfVariables( - point_data_element, rModelPart, mHistoricalVariablesMap); - VtuOutputHelperUtilities::AddListOfVariables( - point_data_element, rModelPart, mNonHistoricalNodalVariablesMap); - VtuOutputHelperUtilities::AddListOfFlags( - point_data_element, rModelPart, mNodalFlagsMap); - VtuOutputHelperUtilities::AddListOfContainerExpressions( - point_data_element, rModelPart, mKratosVtuIndicesMap, mPointContainerExpressionsMap); + + if (rUnstructuredGridData.UsePointsForDataFieldOutput) { + KRATOS_INFO_IF("VtuOutput", mEchoLevel > 2) << "--- Collecting nodal data fields...\n"; + // generate and add point field data + std::vector all_indices(p_nodes->size()); + std::iota(all_indices.begin(), all_indices.end(), 0); + AddFieldsUsingTensorAdaptor(*point_data_element, p_nodes, mFlags[static_cast(Globals::DataLocation::NodeNonHistorical)], *p_xml_data_element_wrapper, r_data_communicator, all_indices, mEchoLevel); + AddFieldsUsingTensorAdaptor(*point_data_element, p_nodes, mVariables[static_cast(Globals::DataLocation::NodeNonHistorical)], *p_xml_data_element_wrapper, r_data_communicator, all_indices, mEchoLevel); + AddFieldsUsingTensorAdaptor(*point_data_element, p_nodes, mVariables[static_cast(Globals::DataLocation::NodeHistorical)], *p_xml_data_element_wrapper, r_data_communicator, all_indices, mEchoLevel, 0); + AddFields(*point_data_element, rUnstructuredGridData.mMapOfPointTensorAdaptors, *p_xml_data_element_wrapper, all_indices, r_data_communicator, mEchoLevel); + } // create cell data - auto cell_data_element = Kratos::make_shared("CellData"); + auto cell_data_element = Kratos::make_shared("CellData"); piece_element->AddElement(cell_data_element); - if (mIsElementsConsidered) { - VtuOutputHelperUtilities::AddListOfVariables( - cell_data_element, rModelPart, mNonHistoricalCellVariablesMap); - VtuOutputHelperUtilities::AddListOfFlags( - cell_data_element, rModelPart, mCellFlagsMap); - } else if (mIsConditionsConsidered) { - VtuOutputHelperUtilities::AddListOfVariables( - cell_data_element, rModelPart, mNonHistoricalCellVariablesMap); - VtuOutputHelperUtilities::AddListOfFlags( - cell_data_element, rModelPart, mCellFlagsMap); + + // generate and add cell field data + if (rUnstructuredGridData.mpCells.has_value()) { + KRATOS_INFO_IF("VtuOutput", mEchoLevel > 2) << "--- Collecting " << GetEntityName(rUnstructuredGridData.mpCells) << " data fields...\n"; + std::visit([this, &rUnstructuredGridData, &cell_data_element, &p_xml_data_element_wrapper, &r_data_communicator, &writing_indices](auto p_container){ + AddFieldsUsingTensorAdaptor(*cell_data_element, p_container, GetContainerMap(this->mVariables, rUnstructuredGridData.mpCells.value()), *p_xml_data_element_wrapper, r_data_communicator, writing_indices, mEchoLevel); + AddFieldsUsingTensorAdaptor(*cell_data_element, p_container, GetContainerMap(this->mFlags, rUnstructuredGridData.mpCells.value()), *p_xml_data_element_wrapper, r_data_communicator, writing_indices, mEchoLevel); + }, rUnstructuredGridData.mpCells.value()); + AddFields(*cell_data_element, rUnstructuredGridData.mMapOfCellTensorAdaptors, *p_xml_data_element_wrapper, writing_indices, r_data_communicator, mEchoLevel); } - VtuOutputHelperUtilities::AddListOfContainerExpressions( - cell_data_element, rModelPart, mKratosVtuIndicesMap, mCellContainerExpressionsMap); + std::stringstream output_vtu_file_name; + output_vtu_file_name << rOutputFileNamePrefix << "/" << rUnstructuredGridData.mpModelPart->FullName(); - const auto& r_communiator = rModelPart.GetCommunicator(); + // identify suffix with the entity type. + const std::string& suffix = "_" + GetEntityName(rUnstructuredGridData.mpCells) + "s"; - std::stringstream output_vtu_file_name; - output_vtu_file_name << rOutputFileNamePrefix; - if (r_communiator.IsDistributed()) { - output_vtu_file_name << "_" << r_communiator.MyPID(); - } - output_vtu_file_name << ".vtu"; + const std::string pvd_data_set_name = rUnstructuredGridData.mpModelPart->FullName() + suffix; + // append with the step value and rank and extension + output_vtu_file_name << suffix << "_" << Step + << (r_data_communicator.IsDistributed() + ? "_" + std::to_string(r_data_communicator.Rank()) + : "") + << ".vtu"; + + // write the vtu file. std::ofstream output_file; - output_file.open(output_vtu_file_name.str(), std::ios::out | std::ios::trunc); + output_file.open(output_vtu_file_name.str(), std::ios::out | std::ios::trunc | std::ios::binary); + output_file << "\n"; + vtk_file_element.Write(output_file); + output_file.close(); - switch (mOutputFormat) { - case WriterFormat::ASCII: - { - XmlOStreamAsciiWriter writer(output_file, mPrecision); - writer.WriteElement(*vtk_file_element); - } - break; - case WriterFormat::BINARY: - { - XmlOStreamBase64BinaryWriter writer(output_file); - writer.WriteElement(*vtk_file_element); + // if it is run on a distributed system, create the pvtu file. + if (r_data_communicator.IsDistributed()) { + return std::make_pair(pvd_data_set_name, + WritePartitionedUnstructuredGridData( + *point_data_element, *cell_data_element, + output_vtu_file_name.str(), r_data_communicator)); + } + + // return the final file name for + return std::make_pair(pvd_data_set_name, output_vtu_file_name.str()); +} + +template +std::pair VtuOutput::WriteIntegrationPointData( + TXmlElementDataWrapperCreateFunctor&& rElementDataWrapperCreateFunctor, + TXmlElementDataWrapperAppendFunctor&& rElementDataWrapperAppendFunctor, + UnstructuredGridData& rUnstructuredGridData, + const std::string& rOutputFileNamePrefix, + const IndexType Step) const +{ + if (!rUnstructuredGridData.mpCells.has_value()) { + // nothing to do here. + return std::make_pair("", ""); + } + + const auto& integration_point_vars = GetContainerMap( + mIntegrationPointVariables, rUnstructuredGridData.mpCells.value()); + + if (integration_point_vars.empty()) { + // nothing to do here. + return std::make_pair("", ""); + } + + // create the vtk file + XmlElementsArray vtk_file_element("VTKFile"); + vtk_file_element.AddAttribute("type", "UnstructuredGrid"); + vtk_file_element.AddAttribute("version", "0.1"); + vtk_file_element.AddAttribute("byte_order", GetEndianness()); + + // create the unstructured grid + auto unstructured_grid_element = Kratos::make_shared("UnstructuredGrid"); + vtk_file_element.AddElement(unstructured_grid_element); + + auto p_xml_data_element_wrapper = rElementDataWrapperCreateFunctor(); + rElementDataWrapperAppendFunctor(vtk_file_element, p_xml_data_element_wrapper); + + DenseVector offsets; + + const auto total_gauss_points = std::visit([&offsets](auto p_container) { + // resize the offsets + offsets.resize(p_container->size(), false); + + IndexType total_number_of_gauss_points = 0; + + // now compute the offsets for each entity. This allows + // having different number of gps in different entities. + // which is the case if we have a model part with mixed type + // of elements. + for (IndexType i = 0; i < p_container->size(); ++i) { + const auto& r_entity = *(p_container->begin() + i); + const auto number_of_gps = r_entity.GetGeometry().IntegrationPointsNumber(r_entity.GetIntegrationMethod()); + total_number_of_gauss_points += number_of_gps; + offsets[i] = total_number_of_gauss_points - number_of_gps; } - break; + + return total_number_of_gauss_points; + }, rUnstructuredGridData.mpCells.value()); + + // create the piece element + auto piece_element = Kratos::make_shared("Piece"); + piece_element->AddAttribute("NumberOfPoints", std::to_string(total_gauss_points)); + piece_element->AddAttribute("NumberOfCells", "0"); + unstructured_grid_element->AddElement(piece_element); + + // construct the gauss point position data + DenseVector gauss_point_nd_data_shape(2); + gauss_point_nd_data_shape[0] = total_gauss_points; + gauss_point_nd_data_shape[1] = 3; + auto gauss_point_positions = Kratos::make_shared>(gauss_point_nd_data_shape); + const auto span = gauss_point_positions->ViewData(); + + std::visit([&span, &offsets](auto p_container){ + IndexPartition(p_container->size()).for_each(array_1d{}, [&span, &p_container, &offsets](const auto Index, auto& rTLS) { + const auto& r_entity = *(p_container->begin() + Index); + const auto number_of_gauss_points = r_entity.GetGeometry().IntegrationPointsNumber(r_entity.GetIntegrationMethod()); + for (IndexType i = 0; i < number_of_gauss_points; ++i) { + r_entity.GetGeometry().GlobalCoordinates(rTLS, i); + std::copy(rTLS.begin(), rTLS.end(), span.begin() + offsets[Index] * 3 + i * 3); + } + + }); + }, rUnstructuredGridData.mpCells.value()); + + // create the gauss points element + auto points_element = Kratos::make_shared("Points"); + points_element->AddElement(p_xml_data_element_wrapper->Get("Position", gauss_point_positions)); + piece_element->AddElement(points_element); + + auto cells_element = Kratos::make_shared("Cells"); + piece_element->AddElement(cells_element); + + // create the point data + auto point_data_element = Kratos::make_shared("PointData"); + piece_element->AddElement(point_data_element); + + const auto& r_data_communicator = mrModelPart.GetCommunicator().GetDataCommunicator(); + + // add the gauss point data + bool is_gauss_point_data_available = false; + for (const auto& r_pair : integration_point_vars) { + std::visit([&offsets, &point_data_element, &p_xml_data_element_wrapper, &rUnstructuredGridData, &is_gauss_point_data_available, &r_data_communicator, total_gauss_points](auto pVariable, auto pContainer) { + // type information of the variable + using data_type = typename BareType::Type; + using data_type_traits = DataTypeTraits; + using primitive_data_type = typename data_type_traits::PrimitiveType; + + if constexpr(std::is_same_v) { + // here we cannot use GaussPointVariableTensorAdaptor because + // it does not allow recording gauss point information if different + // entities have different number of gauss points. + // hence we do the computation here manually. + + std::vector output; + + // first we need to find out the shape of the gauss point data + std::vector local_shape(data_type_traits::Dimension, 0u); + if (!pContainer->empty()) { + pContainer->front().CalculateOnIntegrationPoints( + *pVariable, output, rUnstructuredGridData.mpModelPart->GetProcessInfo()); + + if (!output.empty()) { + // if there are available gauss point information + data_type_traits::Shape(output.front(), local_shape.data(), + local_shape.data() + local_shape.size()); + } + } + + // now do the communication between ranks to get the correct size + const auto& max_local_shape = r_data_communicator.MaxAll(local_shape); + + // now we construct the nd_data_shape + DenseVector nd_data_shape(local_shape.size() + 1); + std::copy(max_local_shape.begin(), max_local_shape.end(), nd_data_shape.begin() + 1); + nd_data_shape[0] = total_gauss_points; + + const auto total_number_of_components = std::accumulate(max_local_shape.begin(), max_local_shape.end(), 1u, std::multiplies{}); + + auto p_gauss_data = Kratos::make_shared>(nd_data_shape); + auto span = p_gauss_data->ViewData(); + + if (r_data_communicator.SumAll(static_cast(span.size())) > 0) { + is_gauss_point_data_available = true; + IndexPartition(pContainer->size()).for_each(std::vector{}, [&span, &pContainer, &pVariable, &rUnstructuredGridData, &offsets, total_number_of_components](const auto Index, auto& rTLS) { + auto& r_entity = *(pContainer->begin() + Index); + r_entity.CalculateOnIntegrationPoints(*pVariable, rTLS, rUnstructuredGridData.mpModelPart->GetProcessInfo()); + DataTypeTraits>::CopyToContiguousData(span.begin() + offsets[Index] * total_number_of_components, rTLS); + }); + point_data_element->AddElement(p_xml_data_element_wrapper->Get(pVariable->Name(), p_gauss_data)); + } + } + }, r_pair.second, rUnstructuredGridData.mpCells.value()); } - output_file.close(); + if (is_gauss_point_data_available) { + std::stringstream output_vtu_file_name; + output_vtu_file_name + << rOutputFileNamePrefix << "/" << rUnstructuredGridData.mpModelPart->FullName() << "_" + << GetEntityName(rUnstructuredGridData.mpCells) + << "_gauss_" << Step + << (r_data_communicator.IsDistributed() + ? "_" + std::to_string(r_data_communicator.Rank()) + : "") + << ".vtu"; - if (r_communiator.IsDistributed()) { - VtuOutputHelperUtilities::WritePvtuFile(vtk_file_element, rModelPart, rOutputFileNamePrefix, - output_vtu_file_name.str()); + std::ofstream output_file; + output_file.open(output_vtu_file_name.str(), std::ios::out | std::ios::trunc); + output_file << "\n"; + vtk_file_element.Write(output_file); + output_file.close(); + + if (r_data_communicator.IsDistributed()) { + return std::make_pair( + rUnstructuredGridData.mpModelPart->FullName() + "_" + GetEntityName(rUnstructuredGridData.mpCells) + "_gauss", + WritePartitionedUnstructuredGridData( + *point_data_element, *Kratos::make_shared(""), + output_vtu_file_name.str(), r_data_communicator)); + } + + return std::make_pair(rUnstructuredGridData.mpModelPart->FullName() + "_" + GetEntityName(rUnstructuredGridData.mpCells) + "_gauss", + output_vtu_file_name.str()); + } + else { + return std::make_pair("", ""); } } -void VtuOutput::ClearHistoricalVariables() +template +void VtuOutput::WriteData( + std::vector>& rPVDFileNameInfo, + TXmlElementDataWrapperCreateFunctor&& rElementDataWrapperCreateFunctor, + TXmlElementDataWrapperAppendFunctor&& rElementDataWrapperAppendFunctor, + UnstructuredGridData& rUnstructuredGridData, + const std::string& rOutputPrefix, + const IndexType Step) const { - mHistoricalVariablesMap.clear(); -} + KRATOS_TRY -void VtuOutput::ClearNodalNonHistoricalVariables() -{ - mNonHistoricalNodalVariablesMap.clear(); -} + rPVDFileNameInfo.push_back(WriteUnstructuredGridData( + rElementDataWrapperCreateFunctor, rElementDataWrapperAppendFunctor, + rUnstructuredGridData, rOutputPrefix, Step)); -void VtuOutput::ClearCellNonHistoricalVariables() -{ - mNonHistoricalCellVariablesMap.clear(); -} + rPVDFileNameInfo.push_back(WriteIntegrationPointData( + rElementDataWrapperCreateFunctor, rElementDataWrapperAppendFunctor, + rUnstructuredGridData, rOutputPrefix, Step)); -void VtuOutput::ClearNodalFlags() -{ - mNodalFlagsMap.clear(); + KRATOS_CATCH(""); } -void VtuOutput::ClearCellFlags() +void VtuOutput::PrintOutput(const std::string& rOutputFileNamePrefix) { - mCellFlagsMap.clear(); -} + KRATOS_TRY -void VtuOutput::ClearNodalContainerExpressions() -{ - mPointContainerExpressionsMap.clear(); + const auto& r_process_info = mrModelPart.GetProcessInfo(); + + // here we do not check whether the r_process_info has the time variable specified + // because, in a const DataValueContainer, if the variable is not there, it returns the + // zero value of the variable. + const double time = r_process_info[TIME]; + + const IndexType step = r_process_info[STEP]; + + std::filesystem::create_directories(rOutputFileNamePrefix); + + std::vector> pvd_file_name_info; + + for (auto& r_unstructured_grid_data : mUnstructuredGridDataList) { + switch (mOutputFormat) { + case ASCII: + { + WriteData( + pvd_file_name_info, + [this](){ return Kratos::make_shared(XmlInPlaceDataElementWrapper::ASCII, this->mPrecision); }, + [](auto& rVtkFileElement, auto pXmlDataElementWrapper) {}, + r_unstructured_grid_data, + rOutputFileNamePrefix, + step); + break; + } + case BINARY: + { + WriteData( + pvd_file_name_info, + [this](){ return Kratos::make_shared(XmlInPlaceDataElementWrapper::BINARY, this->mPrecision); }, + [](auto& rVtkFileElement, auto pXmlDataElementWrapper) { rVtkFileElement.AddAttribute("header_type", "UInt64"); }, + r_unstructured_grid_data, + rOutputFileNamePrefix, + step); + break; + } + case RAW: + { + WriteData( + pvd_file_name_info, + [](){ return Kratos::make_shared(XmlAppendedDataElementWrapper::RAW); }, + [](auto& rVtkFileElement, auto pXmlDataElementWrapper) { rVtkFileElement.AddElement(pXmlDataElementWrapper); rVtkFileElement.AddAttribute("header_type", "UInt64"); }, + r_unstructured_grid_data, + rOutputFileNamePrefix, + step); + break; + } + case COMPRESSED_RAW: + { + WriteData( + pvd_file_name_info, + [](){ return Kratos::make_shared(XmlAppendedDataElementWrapper::COMPRESSED_RAW); }, + [](auto& rVtkFileElement, auto pXmlDataElementWrapper) { rVtkFileElement.AddElement(pXmlDataElementWrapper); rVtkFileElement.AddAttribute("header_type", "UInt64"); rVtkFileElement.AddAttribute("compressor", "vtkZLibDataCompressor"); }, + r_unstructured_grid_data, + rOutputFileNamePrefix, + step); + break; + } + } + } + + // now generate the *.pvd file + if (mrModelPart.GetCommunicator().MyPID() == 0) { + KRATOS_INFO_IF("VtuOutput", mEchoLevel > 1) + << "Writing \"" << mrModelPart.FullName() + << "\" PVD file...\n"; + // Single pvd file links all the vtu files from sum-model parts + // partitioned model_parts and time step vtu files together. + + if (!mIsPVDFileHeaderWritten) { + mIsPVDFileHeaderWritten = true; + + // creates the pvd file element + XmlElementsArray pvd_file_element("VTKFile"); + pvd_file_element.AddAttribute("type", "Collection"); + pvd_file_element.AddAttribute("version", "1.0"); + pvd_file_element.AddAttribute("byte_order", GetEndianness()); + + // creates the collection element + auto collection_element = Kratos::make_shared("Collection"); + pvd_file_element.AddElement(collection_element); + + // now iterate through all the time steps and correctly write + // the file names for each time step. + IndexType local_index = 0; + for (IndexType i = 0; i < pvd_file_name_info.size(); ++i) { + if (pvd_file_name_info[i].second != "") { + auto current_element = Kratos::make_shared("DataSet"); + + // write the time with the specified precision. + std::stringstream str_time; + str_time << std::scientific << std::setprecision(mPrecision) << time; + + current_element->AddAttribute("timestep", str_time.str()); + current_element->AddAttribute("name", pvd_file_name_info[i].first); + current_element->AddAttribute("part", std::to_string(local_index++)); + current_element->AddAttribute( + "file", std::filesystem::relative( + std::filesystem::absolute(pvd_file_name_info[i].second), + std::filesystem::absolute(rOutputFileNamePrefix).parent_path()) + .generic_string()); + collection_element->AddElement(current_element); + } + } + + std::ofstream output_file; + output_file.open(rOutputFileNamePrefix + ".pvd", std::ios::out | std::ios::trunc); + output_file << "\n"; + pvd_file_element.Write(output_file); + output_file.close(); + } else { + std::ofstream output_file; + output_file.open(rOutputFileNamePrefix + ".pvd", std::ios::in | std::ios::out); + output_file.seekp(-28, std::ios::end); + + // now iterate through all the time steps and correctly write + // the file names for each time step. + IndexType local_index = 0; + for (IndexType i = 0; i < pvd_file_name_info.size(); ++i) { + if (pvd_file_name_info[i].second != "") { + auto current_element = Kratos::make_shared("DataSet"); + + // write the time with the specified precision. + std::stringstream str_time; + str_time << std::scientific << std::setprecision(mPrecision) << time; + + current_element->AddAttribute("timestep", str_time.str()); + current_element->AddAttribute("name", pvd_file_name_info[i].first); + current_element->AddAttribute("part", std::to_string(local_index++)); + current_element->AddAttribute( + "file", std::filesystem::relative( + std::filesystem::absolute(pvd_file_name_info[i].second), + std::filesystem::absolute(rOutputFileNamePrefix).parent_path()) + .generic_string()); + + current_element->Write(output_file, 2); + } + } + + output_file << " \n\n"; + output_file.close(); + } + + } + + KRATOS_CATCH(""); } -void VtuOutput::ClearCellContainerExpressions() +std::string VtuOutput::Info() const { - mCellContainerExpressionsMap.clear(); + std::stringstream info; + info << "VtuOutput: " << mrModelPart.FullName() << " [ writer = "; + switch (mOutputFormat) { + case ASCII: + info << "ASCII"; + break; + case BINARY: + info << "BINARY"; + break; + case RAW: + info << "RAW"; + break; + case COMPRESSED_RAW: + info << "COMPRESSED_RAW"; + break; + } + + info << ", precision = " << mPrecision << ", configuration = "; + + switch (mConfiguration){ + case Globals::Configuration::Initial: + info << "initial"; + break; + case Globals::Configuration::Current: + info << "current"; + break; + } + + info << ", echo level = " << mEchoLevel << " ]"; + + return info.str(); } -const ModelPart& VtuOutput::GetModelPart() const +void VtuOutput::PrintInfo(std::ostream& rOStream) const { - return mrModelPart; + rOStream << this->Info(); } -void VtuOutput::PrintOutput(const std::string& rOutputFilenamePrefix) +void VtuOutput::PrintData(std::ostream& rOStream) const { - PrintModelPart(rOutputFilenamePrefix, mrModelPart); + PrintDataLocationData(rOStream, "flag", mFlags); + rOStream << "\n"; + PrintDataLocationData(rOStream, "variable", mVariables); + rOStream << "\n"; + PrintDataLocationData(rOStream, "integration variable", mIntegrationPointVariables); + rOStream << "\n"; + + rOStream << "List of model part info:"; + for (const auto& r_model_part_data : mUnstructuredGridDataList) { + rOStream << "\n\tModel part: \"" << r_model_part_data.mpModelPart->FullName() << "\"" + << " with " << GetEntityName(r_model_part_data.mpCells) << "s" + << ", used for point fields = " << (r_model_part_data.UsePointsForDataFieldOutput ? "yes" : "no"); + + if (r_model_part_data.UsePointsForDataFieldOutput) { + rOStream << "\n\t\t" << "Point fields:"; + for (const auto& r_pair : r_model_part_data.mMapOfPointTensorAdaptors) { + std::visit([&rOStream, &r_pair](auto pNDData){ + rOStream << "\n\t\t\t" << r_pair.first << ": " << *pNDData; + }, r_pair.second); + } + } + + rOStream << "\n\t\t" << "Cell fields:"; + for (const auto& r_pair : r_model_part_data.mMapOfCellTensorAdaptors) { + std::visit([&rOStream, &r_pair](auto pNDData){ + rOStream << "\n\t\t\t" << r_pair.first << ": " << *pNDData; + }, r_pair.second); + } + } } // template instantiations -template KRATOS_API(KRATOS_CORE) void VtuOutput::AddHistoricalVariable(const Variable&); -template KRATOS_API(KRATOS_CORE) void VtuOutput::AddHistoricalVariable(const Variable&); -template KRATOS_API(KRATOS_CORE) void VtuOutput::AddHistoricalVariable(const Variable>&); -template KRATOS_API(KRATOS_CORE) void VtuOutput::AddHistoricalVariable(const Variable>&); -template KRATOS_API(KRATOS_CORE) void VtuOutput::AddHistoricalVariable(const Variable>&); -template KRATOS_API(KRATOS_CORE) void VtuOutput::AddHistoricalVariable(const Variable>&); - -template KRATOS_API(KRATOS_CORE) void VtuOutput::AddNonHistoricalVariable(const Variable&, const Flags&); -template KRATOS_API(KRATOS_CORE) void VtuOutput::AddNonHistoricalVariable(const Variable&, const Flags&); -template KRATOS_API(KRATOS_CORE) void VtuOutput::AddNonHistoricalVariable(const Variable>&, const Flags&); -template KRATOS_API(KRATOS_CORE) void VtuOutput::AddNonHistoricalVariable(const Variable>&, const Flags&); -template KRATOS_API(KRATOS_CORE) void VtuOutput::AddNonHistoricalVariable(const Variable>&, const Flags&); -template KRATOS_API(KRATOS_CORE) void VtuOutput::AddNonHistoricalVariable(const Variable>&, const Flags&); - -template KRATOS_API(KRATOS_CORE) void VtuOutput::AddContainerExpression(const std::string&, const typename ContainerExpression::Pointer); -template KRATOS_API(KRATOS_CORE) void VtuOutput::AddContainerExpression(const std::string&, const typename ContainerExpression::Pointer); -template KRATOS_API(KRATOS_CORE) void VtuOutput::AddContainerExpression(const std::string&, const typename ContainerExpression::Pointer); +#ifndef KRATOS_VTU_OUTPUT_VARIABLE_METHOD_INSTANTIATION +#define KRATOS_VTU_OUTPUT_VARIABLE_METHOD_INSTANTIATION(...) \ + template KRATOS_API(KRATOS_CORE) void VtuOutput::AddVariable<__VA_ARGS__>(const Variable<__VA_ARGS__>&, const Globals::DataLocation&); \ + template KRATOS_API(KRATOS_CORE) void VtuOutput::AddIntegrationPointVariable<__VA_ARGS__>(const Variable<__VA_ARGS__>&, const Globals::DataLocation&); \ + +#endif + +#ifndef KRATOS_VTU_OUTPUT_TENSOR_METHOD_INSTANTIATION +#define KRATOS_VTU_OUTPUT_TENSOR_METHOD_INSTANTIATION(DATA_TYPE) \ + template KRATOS_API(KRATOS_CORE) void VtuOutput::AddTensorAdaptor::Pointer>(const std::string&, TensorAdaptor::Pointer); \ + template KRATOS_API(KRATOS_CORE) void VtuOutput::ReplaceTensorAdaptor::Pointer>(const std::string&, TensorAdaptor::Pointer); \ + template KRATOS_API(KRATOS_CORE) void VtuOutput::EmplaceTensorAdaptor::Pointer>(const std::string&, TensorAdaptor::Pointer); \ + +#endif + +KRATOS_VTU_OUTPUT_VARIABLE_METHOD_INSTANTIATION(int) +KRATOS_VTU_OUTPUT_VARIABLE_METHOD_INSTANTIATION(double) +KRATOS_VTU_OUTPUT_VARIABLE_METHOD_INSTANTIATION(array_1d) +KRATOS_VTU_OUTPUT_VARIABLE_METHOD_INSTANTIATION(array_1d) +KRATOS_VTU_OUTPUT_VARIABLE_METHOD_INSTANTIATION(array_1d) +KRATOS_VTU_OUTPUT_VARIABLE_METHOD_INSTANTIATION(array_1d) +KRATOS_VTU_OUTPUT_VARIABLE_METHOD_INSTANTIATION(Vector) +KRATOS_VTU_OUTPUT_VARIABLE_METHOD_INSTANTIATION(Matrix) + +KRATOS_VTU_OUTPUT_TENSOR_METHOD_INSTANTIATION(bool) +KRATOS_VTU_OUTPUT_TENSOR_METHOD_INSTANTIATION(int) +KRATOS_VTU_OUTPUT_TENSOR_METHOD_INSTANTIATION(double) + +#undef KRATOS_VTU_OUTPUT_VARIABLE_METHOD_INSTANTIATION +#undef KRATOS_VTU_OUTPUT_TENSOR_METHOD_INSTANTIATION } // namespace Kratos diff --git a/kratos/input_output/vtu_output.h b/kratos/input_output/vtu_output.h index 50e56382dd4d..45b6e59a4373 100644 --- a/kratos/input_output/vtu_output.h +++ b/kratos/input_output/vtu_output.h @@ -13,30 +13,48 @@ #pragma once // System includes +#include #include #include -#include -#include // External includes // Project includes +#include "containers/flags.h" +#include "containers/nd_data.h" +#include "containers/variable.h" #include "includes/define.h" +#include "includes/global_variables.h" #include "includes/io.h" #include "includes/model_part.h" -#include "containers/variable.h" -#include "containers/flags.h" -#include "expression/container_expression.h" +#include "tensor_adaptors/tensor_adaptor.h" +#include "utilities/xml_utilities/xml_data_element_wrapper.h" namespace Kratos { + /** * @class VtuOutput - * @brief Class to output Kratos Flags, Variables and ContainerExpressions - * to vtu. Supports both shared and distributed memory architectures. - * - * @details This class does not create or destroy any folder structures, hence the output - * file name prefix should have a valid parent directory. + * @brief Handles VTU (Visualization Toolkit Unstructured grid) output for Kratos ModelParts. * @author Suneth Warnakulasuriya + * @ingroup KratosCore + * + * This class provides functionality to export simulation data from a Kratos ModelPart to VTU files, + * supporting both ASCII, BINARY, RAW and COMPRESSED_RAW with zlib compression. It allows users to register @ref Variable , @ref Flags , + * and @ref TensorAdaptor for output, and supports writing data on nodes, elements, conditions, and integration points. + * The output can be configured to include submodel parts and supports parallel execution (MPI). + * + * @section vtu_output_usage Usage + * This output put process can be used at any point in the simulation (static or dynamic). But, upon construction of an object of + * @ref VtuOutput, all the variables, flags, integration point variables and tensor adaptors should be added + * using @ref AddFlag, @ref AddVariable, @ref AddIntegrationPointVariable or @ref AddTensorAdaptor . Once the + * @ref PrintOutput is called, no more data fields can be added because Vtk library does not support varying fields. + * + * But, already added @ref TensorAdaptor objects may be replaced with new @ref TensorAdaptor objects after calling @ref PrintOutput + * by using @ref ReplaceTensorAdaptor method. + * + * A convenience method called @ref EmplaceTensorAdaptor is there to add the @ref TensorAdaptor if it is not existing and if the call is + * before the first call of @ref PrintOutput. Otherwise, it will try replacing an existing @ref TensorAdaptor. + * */ class KRATOS_API(KRATOS_CORE) VtuOutput : public IO { @@ -44,26 +62,48 @@ class KRATOS_API(KRATOS_CORE) VtuOutput : public IO ///@name Type definitions ///@{ + // Index type definition using IndexType = std::size_t; - using SupportedVariables = std::variant< - const Variable*, - const Variable*, - const Variable>*, - const Variable>*, - const Variable>*, - const Variable>*>; - - using SupportedCellContainerExpressions = std::variant< - ContainerExpression::Pointer, - ContainerExpression::Pointer>; + // Variant defining supported container (i.e. @ref PointerVectorSet ) type pointers. + using SupportedContainerPointerType = std::variant< + ModelPart::NodesContainerType::Pointer, + ModelPart::ConditionsContainerType::Pointer, + ModelPart::ElementsContainerType::Pointer + >; + + // Variant defining supported cell type @ref PointerVectorSte which can be visualized with cell data with vtk library. + using CellContainerPointerType = std::variant< + ModelPart::ConditionsContainerType::Pointer, + ModelPart::ElementsContainerType::Pointer + >; + + // Variant defining all the @ref Variable types which are supported to be visualized at point or cell data with vtk library. + using SupportedVariablePointerType = std::variant< + Variable const *, + Variable const *, + Variable> const *, + Variable> const *, + Variable> const *, + Variable> const *, + Variable const *, + Variable const * + >; + + // Variant definining all the supported @ref TensorAdaptor which can be used to pass data fields to point or cell data using the vtk library. + using SupportedTensorAdaptorPointerType = std::variant< + TensorAdaptor::Pointer, + TensorAdaptor::Pointer, + TensorAdaptor::Pointer + >; + + + // A list of maps of name and a @p T for different locations ( @ref Globals::DataLocation ) which are used for output at later time. + template + using DataList = std::array, static_cast(Kratos::Globals::DataLocation::NumberOfDataLocations)>; KRATOS_CLASS_POINTER_DEFINITION(VtuOutput); - KRATOS_DEFINE_LOCAL_FLAG( NODES ); - KRATOS_DEFINE_LOCAL_FLAG( CONDITIONS ); - KRATOS_DEFINE_LOCAL_FLAG( ELEMENTS ); - ///@} ///@name Public enums ///@{ @@ -71,8 +111,20 @@ class KRATOS_API(KRATOS_CORE) VtuOutput : public IO /// Enumerations for the output writer format. enum WriterFormat { - ASCII, /// ASCII format. - BINARY /// Binary format. + ASCII, ///< ASCII format. + BINARY, ///< Binary format. + RAW, ///< Raw format. All data is appended to one stream. + COMPRESSED_RAW ///< Data is first compressed with zlib and the appended to one stream. + }; + + struct UnstructuredGridData + { + bool UsePointsForDataFieldOutput; // If true, then the mpPoints represents a container in the model part, otherwise, mpPoints refers to a container which is on the fly generated. + ModelPart * mpModelPart; // Model part associated with the unstructured grid data. + ModelPart::NodesContainerType::Pointer mpPoints; // Points to be used in the unstructured grid. + std::optional mpCells; // Cells to be used in the unstructured grid. + std::map mMapOfPointTensorAdaptors; // Point data tensor adaptors. + std::map mMapOfCellTensorAdaptors; // Cell data tensor adaptors. }; ///@} @@ -80,108 +132,153 @@ class KRATOS_API(KRATOS_CORE) VtuOutput : public IO ///@{ /** - * @brief Construct a new Vtu Output IO - * @details Constructs a new VtuOuput IO instance with the given parameters. - * @param rModelPart Model part to be used. - * @param IsInitialConfiguration If true, the initial configuration is written. - * @param OutputFormat Output format. Either ASCII or BINARY supported. - * @param Precision Precision of the double output. + * @brief Construct a new Vtu Output + * + * @param rModelPart Model part to be used in the vtu output. + * @param Configuration Which nodal positions to be written out. + * @param OutputFormat The format of the output. + * @param Precision Precision of the double values to be used when writing the doubles as ASCII. + * @param OutputSubModelParts To consider all the submodel parts recursively for output. + * @param WriteIds To write ids under the name "KRATOS_ID" to be visualized. + * @param EchoLevel Echo level for to print information. */ VtuOutput( ModelPart& rModelPart, - const bool IsInitialConfiguration = true, - const WriterFormat OutputFormat = WriterFormat::BINARY, - const IndexType Precision = 9); + const Globals::Configuration Configuration, + const WriterFormat OutputFormat = WriterFormat::COMPRESSED_RAW, + const IndexType Precision = 9, + const bool OutputSubModelParts = false, + const bool WriteIds = false, + const IndexType EchoLevel = 0); ///@} ///@name Public operations ///@{ /** - * @brief Adds historical variables to the output. + * @brief Adds a flag to the VTU output. * - * @tparam TDataType - * @param rVariable + * This method registers a flag @p rFlagVariable to be included in the VTU output file. + * The flag will be associated with the specified data location (e.g., node, element, condition, refer @ref Globals::DataLocation ) + * given by @p DataLocation . This allows the Flag's values to be written to the output file + * when @ref PrintOutput is called with the name @p rFlagName. + * + * @throws std::runtime_error if @ref AddFlag is called after @ref PrintOutput. + * @throws std::runtime_error if tries to add the same @p rFlagName more than ones. + * @throws std::runtime_error if there already exist a field name same as @p rFlagName in one of the compatible data locations with @p DataLocation . + * @throws std::runtime_error if @p DataLocation is not NodeNonHistorical, Condition, or Element. + * + * @param rFlagName The name of the flag to be added. + * @param rFlagVariable The flag variable to be added. + * @param DataLocation The location where the flag data is stored (e.g., NodeNonHistorical, Condition, Element). + * + * @see @ref FlagsTensorAdaptor */ - template - void AddHistoricalVariable(const Variable& rVariable); + void AddFlag( + const std::string& rFlagName, + const Flags& rFlagVariable, + const Globals::DataLocation& DataLocation); /** - * @brief Adds non historical variables to the output. + * @brief Adds a variable to the output for a specified data location. + * + * Registers the given @p rVariable to be included in the VTU output at the specified + * @p DataLocation (e.g., NodeHistorical, NodeNonHistorical, Condition, or Element, refer @ref Globals::DataLocation). + * This allows the variable's values to be written to the output file when @ref PrintOutput is called. * - * @tparam TDataType + * @throws std::runtime_error if @ref AddVariable is called after @ref PrintOutput. + * @throws std::runtime_error if tries to add the same @p rVariable more than ones. + * @throws std::runtime_error if there already exist a field name same as @p rVariable in one of the compatible data locations with @p DataLocation . + * @throws std::runtime_error if @p DataLocation is not NodeHistorical, NodeNonHistorical, Condition, or Element. + * + * @tparam TDataType Data type of the variable. * @param rVariable Variable to be added. - * @param rEntityFlags Considered container for the variable. Either NODES, CONDITIONS or ELEMENTS + * @param DataLocation The location in the model where the variable is defined (e.g., NodeHistorical, NodeNonHistorical, Condition, or Element). + * + * @see @ref VariableTensorAdaptor + * @see @ref HistoricalVariableTensorAdaptor */ template - void AddNonHistoricalVariable( + void AddVariable( const Variable& rVariable, - const Flags& rEntityFlags); + const Globals::DataLocation& DataLocation); /** - * @brief Adds flag output. + * @brief Adds a variable to be output at integration points. * - * @param rFlagName Flag name. - * @param rFlagVariable Variable to be added. - * @param rEntityFlags Considered container for the variable. Either NODES, CONDITIONS or ELEMENTS + * This method registers a @p rVariable for output at the integration points of the mesh elements or conditions + * specified by @p DataLocation (refer @ref Globals::DataLocation ). This allows the entities variable's integration point values to + * be written to the output file when @ref PrintOutput is called. + * + * @throws std::runtime_error if @ref AddIntegrationPointVariable is called after @ref PrintOutput. + * @throws std::runtime_error if tries to add the same @p rVariable more than ones. + * @throws std::runtime_error if there already exist a field name same as @p rVariable in one of the compatible data locations with @p DataLocation . + * @throws std::runtime_error if @p DataLocation is not Condition or Element. + * + * @tparam TDataType Data type of the variable. + * @param rVariable Variable to be added. + * @param DataLocation Specifies the location (e.g., Condition or Element) where the variable is used to calculate integration point values. */ - void AddFlagVariable( - const std::string& rFlagName, - const Flags& rFlagVariable, - const Flags& rEntityFlags); + template + void AddIntegrationPointVariable( + const Variable& rVariable, + const Globals::DataLocation& DataLocation); /** - * @brief Adds container expressions to the vtu output. + * @brief Adds a tensor adaptor to the output. * - * This adds container expressions to the output. Proper care should be taken when updating ContainerExpressions because - * In python, when a container expression is assigned with a new container expression, it does not call the assignment operator. - * Hence, the new expression takes place. Therefore, when container expressions required to be outputted, then it is best - * to always clear the existing container expressions and add the new ones. Otherwise, the vtu output may be writing not the - * latest container expression. + * Registers a @p pTensorAdaptor with the specified @p TensorAdaptorName for the the vtu output. this does not + * copy the tensor adaptor. When @ref PrintOutput is called, the values of the @p pTensorAdaptor at this point will + * be written to vtu. * - * @tparam TContainerType - * @param rExpressionName Name for the container expression. - * @param pContainerExpression Container expression. + * @throws std::runtime_error if @ref AddTensorAdaptor is called after @ref PrintOutput. + * @throws std::runtime_error if tries to add the same @p rTensorAdaptorName more than ones. + * @throws std::runtime_error if there already exist a field name same as @p rTensorAdaptorName in one of the compatible data locations represented by the container of @p pTensorAdaptor . + * @throws std::runtime_error if @p pTensorAdaptor does not corresponds to any of the containers which is written by this @ref VtuOutput . + * + * @tparam TTensorAdaptorPointerType Pointer type of the tensor adaptor. + * @param rTensorAdaptorName The name to associate with the tensor adaptor. + * @param pTensorAdaptor Pointer to the tensor adaptor to be added. */ - template - void AddContainerExpression( - const std::string& rExpressionName, - const typename ContainerExpression::Pointer pContainerExpression); - - /** - * @brief Clears the historical variables. - */ - void ClearHistoricalVariables(); - - /** - * @brief Clears the nodal non-historical variables. - */ - void ClearNodalNonHistoricalVariables(); + template + void AddTensorAdaptor( + const std::string& rTensorAdaptorName, + TTensorAdaptorPointerType pTensorAdaptor); /** - * @brief Clears the cell non-historical variables. - */ - void ClearCellNonHistoricalVariables(); - - /** - * @brief Clears the nodal flags. - */ - void ClearNodalFlags(); - - /** - * @brief Clears the cell flags. - */ - void ClearCellFlags(); - - /** - * @brief Clears the nodal container expressions. - */ - void ClearNodalContainerExpressions(); + * @brief Updates the tensor adaptor associated with the given name. + * + * This method assigns a new tensor adaptor to the specified name, allowing + * for dynamic changes to the tensor adaptor used in the @ref VtuOutput process. + * This also copies the internal data of @p pTensorAdaptor to vtu output's internal data. + * + * @throws std::runtime_error if there is no field name same as @p rTensorAdaptorName in one of the compatible data locations represented by the container of @p pTensorAdaptor . + * @throws std::runtime_error if @p pTensorAdaptor does not corresponds to any of the containers which is written by this @ref VtuOutput . + * + * @tparam TTensorAdaptorPointerType Pointer type of the tensor adaptor. + * @param rTensorAdaptorName The name identifying the tensor adaptor to update. + * @param pTensorAdaptor Pointer to the new tensor adaptor to be associated. + */ + template + void ReplaceTensorAdaptor( + const std::string& rTensorAdaptorName, + TTensorAdaptorPointerType pTensorAdaptor); /** - * @brief Clears the cell container expressions. - */ - void ClearCellContainerExpressions(); + * @brief Inserts a @ref TensorAdaptor into the internal storage with the specified name. + * + * This method: + * - If PrintOutput is not called at all, then calls @ref AddTensorAdaptor + * - If PrintOutput is at least once called, then calls @ref ReplaceTensorAdaptor + * + * @tparam TTensorAdaptorPointerType Pointer type of the tensor adaptor. + * @param rTensorAdaptorName The name to associate with the @ref TensorAdaptor. + * @param pTensorAdaptor Pointer to the @ref TensorAdaptor to be stored. + */ + template + void EmplaceTensorAdaptor( + const std::string& rTensorAdaptorName, + TTensorAdaptorPointerType pTensorAdaptor); /** * @brief Returns the model part. @@ -190,62 +287,96 @@ class KRATOS_API(KRATOS_CORE) VtuOutput : public IO const ModelPart& GetModelPart() const; /** - * @brief Writes the Vtu file. - * @details This writes the final vtu file. If this is a transient output, then @ref rOutputFilenamePrefix - * should have indication of the step, otherwise this will overwrite the same file. - * In the MPI case, this will create one .vtu file per rank, and a .pvtu file to combine them. - * @param rOutputFilenamePrefix Output file name prefix. + * @brief Get the list of output containers + * @details This method returns containers of the model part which are used when writing fields. + * @return std::vector List of container which are used in when writing fields. + */ + std::vector GetOutputContainerList() const; + + /** + * @brief Prints the vtu output data to a file with the specified filename prefix. + * + * Will create the folder with the provided @p rOutputFilenamePrefix . In this folder, following files will be created. + * - One vtu file per timestep, per model part's container (Including sub model parts if @p OutputSubModelParts is true) (in MPI, per rank as well). + * - If it find any gauss point fields, then there will be a vtu file per time step, per model part's container (in MPI, per rank as well). + * - If this is called in MPI, then this will create one pvtu file per timestep, per model part's container (will be having information of all the corresponding rank vtu files) + * - If this is called in MPI, then this will create one pvtu file per timestep, per model part's gauss point container (will be having information of all the corresponding rank vtu files) + * + * Finally it will create one pvd ( @p rOutputFilenamePrefix .pvd ) file for all the model parts, all the timesteps all the gauss point container linking + * - In MPI the pvtu files created. + * - In shared memory parallelism the vtu files created. + * + * @param rOutputFilenamePrefix The prefix to use for the output filename. */ void PrintOutput(const std::string& rOutputFilenamePrefix); ///@} -private: - ///@name Private member variables + ///@name Input and output ///@{ - ModelPart& mrModelPart; /// Reference to the model part. + /// Turn back information as a string. + std::string Info() const override; - const bool mIsInitialConfiguration; /// Flag indicating if it is the initial configuration. + /// Print information about this object. + void PrintInfo(std::ostream& rOStream) const override; - const WriterFormat mOutputFormat; /// The output format for writing the model part. + /// Print object's data. + void PrintData(std::ostream& rOStream) const override; - const IndexType mPrecision; /// The precision used for writing floating-point values. + ///@} - bool mIsConditionsConsidered; /// Flag indicating if conditions are considered. +private: + ///@name Private member variables + ///@{ - bool mIsElementsConsidered; /// Flag indicating if elements are considered. + bool mIsPVDFileHeaderWritten; - // TODO: In the future study to replace the std::map - // TODO: Study replace string, expensive, with hashes or keys + ModelPart& mrModelPart; - std::unordered_map mKratosVtuIndicesMap; /// Map to store Kratos VTU indices. + const Globals::Configuration mConfiguration; - std::map mHistoricalVariablesMap; /// Map to store supported historical variables. + const IndexType mEchoLevel; - std::map mNonHistoricalNodalVariablesMap; /// Map to store supported non-historical nodal variables. + const WriterFormat mOutputFormat; - std::map mNonHistoricalCellVariablesMap; /// Map to store supported non-historical cell variables. + const IndexType mPrecision; - std::map mNodalFlagsMap; /// Map to store nodal flags. + DataList mFlags; - std::map mCellFlagsMap; /// Map to store cell flags. + DataList mVariables; - std::map::Pointer> mPointContainerExpressionsMap; /// Map to store point container expressions. + DataList mIntegrationPointVariables; - std::map mCellContainerExpressionsMap; /// Map to store supported cell container expressions. + std::vector mUnstructuredGridDataList; ///@} ///@name Private operations ///@{ - /** - * @brief Writes the model part to a file. - * @param rOutputFileNamePrefix The output file name prefix. - * @param rModelPart The model part to write. - */ - void PrintModelPart( - const std::string& rOutputFileNamePrefix, - ModelPart& rModelPart) const; + template + void WriteData( + std::vector>& rPVDFileNameInfo, + TXmlElementDataWrapperCreateFunctor&& rElementDataWrapperCreateFunctor, + TXmlElementDataWrapperAppendFunctor&& rElementDataWrapperAppendFunctor, + UnstructuredGridData& rUnstructuredGridData, + const std::string& rOutputPrefix, + const IndexType Step) const; + + template + std::pair WriteUnstructuredGridData( + TXmlElementDataWrapperCreateFunctor&& rElementDataWrapperCreateFunctor, + TXmlElementDataWrapperAppendFunctor&& rElementDataWrapperAppendFunctor, + UnstructuredGridData& rUnstructuredGridData, + const std::string& rOutputPrefix, + const IndexType Step) const; + + template + std::pair WriteIntegrationPointData( + TXmlElementDataWrapperCreateFunctor&& rElementDataWrapperCreateFunctor, + TXmlElementDataWrapperAppendFunctor&& rElementDataWrapperAppendFunctor, + UnstructuredGridData& rUnstructuredGridData, + const std::string& rOutputPrefix, + const IndexType Step) const; ///@} }; From 2db0a091ee71f6c84537eec49d97db013b99cf80 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 20 Feb 2026 07:50:32 +0100 Subject: [PATCH 101/116] fix python bindings --- kratos/future/python/add_io_to_python.cpp | 52 ----------------- kratos/python/add_io_to_python.cpp | 69 +++++++++++++---------- 2 files changed, 40 insertions(+), 81 deletions(-) diff --git a/kratos/future/python/add_io_to_python.cpp b/kratos/future/python/add_io_to_python.cpp index c627adbf6949..a89ebf9d3f06 100644 --- a/kratos/future/python/add_io_to_python.cpp +++ b/kratos/future/python/add_io_to_python.cpp @@ -16,7 +16,6 @@ // Project includes #include "includes/define_python.h" -#include "future/input_output/vtu_output.h" // Include base h #include "add_io_to_python.h" @@ -27,57 +26,6 @@ namespace Kratos::Future::Python void AddIOToPython(pybind11::module& m) { namespace py = pybind11; - - auto vtu_output = py::class_(m, "VtuOutput"); - - py::enum_(vtu_output, "WriterFormat") - .value("ASCII", VtuOutput::WriterFormat::ASCII) - .value("BINARY", VtuOutput::WriterFormat::BINARY) - .value("RAW", VtuOutput::WriterFormat::RAW) - .value("COMPRESSED_RAW", VtuOutput::WriterFormat::COMPRESSED_RAW) - .export_values() - ; - - vtu_output - .def(py::init(), - py::arg("model_part"), - py::arg("configuration") = Globals::Configuration::Initial, - py::arg("output_format") = VtuOutput::WriterFormat::COMPRESSED_RAW, - py::arg("precision") = 9, - py::arg("output_sub_model_parts") = false, - py::arg("write_ids") = false, - py::arg("echo_level") = 0) - .def("AddFlag", &VtuOutput::AddFlag, py::arg("flag_name"), py::arg("flag"), py::arg("data_location")) - .def("AddVariable", &VtuOutput::AddVariable, py::arg("variable"), py::arg("data_location")) - .def("AddVariable", &VtuOutput::AddVariable, py::arg("variable"), py::arg("data_location")) - .def("AddVariable", &VtuOutput::AddVariable>, py::arg("variable"), py::arg("data_location")) - .def("AddVariable", &VtuOutput::AddVariable>, py::arg("variable"), py::arg("data_location")) - .def("AddVariable", &VtuOutput::AddVariable>, py::arg("variable"), py::arg("data_location")) - .def("AddVariable", &VtuOutput::AddVariable>, py::arg("variable"), py::arg("data_location")) - .def("AddVariable", &VtuOutput::AddVariable, py::arg("variable"), py::arg("data_location")) - .def("AddVariable", &VtuOutput::AddVariable, py::arg("variable"), py::arg("data_location")) - .def("AddIntegrationPointVariable", &VtuOutput::AddIntegrationPointVariable, py::arg("variable"), py::arg("data_location")) - .def("AddIntegrationPointVariable", &VtuOutput::AddIntegrationPointVariable, py::arg("variable"), py::arg("data_location")) - .def("AddIntegrationPointVariable", &VtuOutput::AddIntegrationPointVariable>, py::arg("variable"), py::arg("data_location")) - .def("AddIntegrationPointVariable", &VtuOutput::AddIntegrationPointVariable>, py::arg("variable"), py::arg("data_location")) - .def("AddIntegrationPointVariable", &VtuOutput::AddIntegrationPointVariable>, py::arg("variable"), py::arg("data_location")) - .def("AddIntegrationPointVariable", &VtuOutput::AddIntegrationPointVariable>, py::arg("variable"), py::arg("data_location")) - .def("AddIntegrationPointVariable", &VtuOutput::AddIntegrationPointVariable, py::arg("variable"), py::arg("data_location")) - .def("AddIntegrationPointVariable", &VtuOutput::AddIntegrationPointVariable, py::arg("variable"), py::arg("data_location")) - .def("AddTensorAdaptor", &VtuOutput::AddTensorAdaptor::Pointer>, py::arg("tensor_adaptor_name"), py::arg("tensor_adaptor")) - .def("AddTensorAdaptor", &VtuOutput::AddTensorAdaptor::Pointer>, py::arg("tensor_adaptor_name"), py::arg("tensor_adaptor")) - .def("AddTensorAdaptor", &VtuOutput::AddTensorAdaptor::Pointer>, py::arg("tensor_adaptor_name"), py::arg("tensor_adaptor")) - .def("ReplaceTensorAdaptor", &VtuOutput::ReplaceTensorAdaptor::Pointer>, py::arg("tensor_adaptor_name"), py::arg("tensor_adaptor")) - .def("ReplaceTensorAdaptor", &VtuOutput::ReplaceTensorAdaptor::Pointer>, py::arg("tensor_adaptor_name"), py::arg("tensor_adaptor")) - .def("ReplaceTensorAdaptor", &VtuOutput::ReplaceTensorAdaptor::Pointer>, py::arg("tensor_adaptor_name"), py::arg("tensor_adaptor")) - .def("EmplaceTensorAdaptor", &VtuOutput::EmplaceTensorAdaptor::Pointer>, py::arg("tensor_adaptor_name"), py::arg("tensor_adaptor")) - .def("EmplaceTensorAdaptor", &VtuOutput::EmplaceTensorAdaptor::Pointer>, py::arg("tensor_adaptor_name"), py::arg("tensor_adaptor")) - .def("EmplaceTensorAdaptor", &VtuOutput::EmplaceTensorAdaptor::Pointer>, py::arg("tensor_adaptor_name"), py::arg("tensor_adaptor")) - .def("GetModelPart", &VtuOutput::GetModelPart, py::return_value_policy::reference) - .def("GetOutputContainerList", &VtuOutput::GetOutputContainerList) - .def("PrintOutput", &VtuOutput::PrintOutput, py::arg("output_file_name_prefix")) - .def("__str__", PrintObject) - ; } } // namespace Kratos::Python. diff --git a/kratos/python/add_io_to_python.cpp b/kratos/python/add_io_to_python.cpp index 71c5d3c35509..5eb4623153d3 100644 --- a/kratos/python/add_io_to_python.cpp +++ b/kratos/python/add_io_to_python.cpp @@ -209,40 +209,51 @@ void AddIOToPython(pybind11::module& m) py::enum_(vtu_output, "WriterFormat") .value("ASCII", VtuOutput::WriterFormat::ASCII) .value("BINARY", VtuOutput::WriterFormat::BINARY) - .export_values(); + .value("RAW", VtuOutput::WriterFormat::RAW) + .value("COMPRESSED_RAW", VtuOutput::WriterFormat::COMPRESSED_RAW) + .export_values() + ; vtu_output - .def(py::init(), py::arg("model_part"), py::arg("is_initial_configuration_considered") = true, py::arg("binary_output") = VtuOutput::WriterFormat::BINARY, py::arg("precision") = 9) - .def("AddHistoricalVariable", &VtuOutput::AddHistoricalVariable, py::arg("int_variable")) - .def("AddHistoricalVariable", &VtuOutput::AddHistoricalVariable, py::arg("double_variable")) - .def("AddHistoricalVariable", &VtuOutput::AddHistoricalVariable>, py::arg("array3_variable")) - .def("AddHistoricalVariable", &VtuOutput::AddHistoricalVariable>, py::arg("array4_variable")) - .def("AddHistoricalVariable", &VtuOutput::AddHistoricalVariable>, py::arg("array6_variable")) - .def("AddHistoricalVariable", &VtuOutput::AddHistoricalVariable>, py::arg("array9_variable")) - .def("AddNonHistoricalVariable", &VtuOutput::AddNonHistoricalVariable, py::arg("int_variable"), py::arg("entity_flags")) - .def("AddNonHistoricalVariable", &VtuOutput::AddNonHistoricalVariable, py::arg("double_variable"), py::arg("entity_flags")) - .def("AddNonHistoricalVariable", &VtuOutput::AddNonHistoricalVariable>, py::arg("array3_variable"), py::arg("entity_flags")) - .def("AddNonHistoricalVariable", &VtuOutput::AddNonHistoricalVariable>, py::arg("array4_variable"), py::arg("entity_flags")) - .def("AddNonHistoricalVariable", &VtuOutput::AddNonHistoricalVariable>, py::arg("array6_variable"), py::arg("entity_flags")) - .def("AddNonHistoricalVariable", &VtuOutput::AddNonHistoricalVariable>, py::arg("array9_variable"), py::arg("entity_flags")) - .def("AddFlagVariable", &VtuOutput::AddFlagVariable, py::arg("flag_variable_name"), py::arg("flag"), py::arg("entity_flags")) - .def("AddContainerExpression", &VtuOutput::AddContainerExpression, py::arg("container_expression_name"), py::arg("container_expression")) - .def("AddContainerExpression", &VtuOutput::AddContainerExpression, py::arg("container_expression_name"), py::arg("container_expression")) - .def("AddContainerExpression", &VtuOutput::AddContainerExpression, py::arg("container_expression_name"), py::arg("container_expression")) - .def("ClearHistoricalVariables", &VtuOutput::ClearHistoricalVariables) - .def("ClearNodalNonHistoricalVariables", &VtuOutput::ClearNodalNonHistoricalVariables) - .def("ClearNodalFlags", &VtuOutput::ClearNodalFlags) - .def("ClearCellNonHistoricalVariables", &VtuOutput::ClearCellNonHistoricalVariables) - .def("ClearCellFlags", &VtuOutput::ClearCellFlags) - .def("ClearNodalContainerExpressions", &VtuOutput::ClearNodalContainerExpressions) - .def("ClearCellContainerExpressions", &VtuOutput::ClearCellContainerExpressions) + .def(py::init(), + py::arg("model_part"), + py::arg("configuration") = Globals::Configuration::Initial, + py::arg("output_format") = VtuOutput::WriterFormat::COMPRESSED_RAW, + py::arg("precision") = 9, + py::arg("output_sub_model_parts") = false, + py::arg("write_ids") = false, + py::arg("echo_level") = 0) + .def("AddFlag", &VtuOutput::AddFlag, py::arg("flag_name"), py::arg("flag"), py::arg("data_location")) + .def("AddVariable", &VtuOutput::AddVariable, py::arg("variable"), py::arg("data_location")) + .def("AddVariable", &VtuOutput::AddVariable, py::arg("variable"), py::arg("data_location")) + .def("AddVariable", &VtuOutput::AddVariable>, py::arg("variable"), py::arg("data_location")) + .def("AddVariable", &VtuOutput::AddVariable>, py::arg("variable"), py::arg("data_location")) + .def("AddVariable", &VtuOutput::AddVariable>, py::arg("variable"), py::arg("data_location")) + .def("AddVariable", &VtuOutput::AddVariable>, py::arg("variable"), py::arg("data_location")) + .def("AddVariable", &VtuOutput::AddVariable, py::arg("variable"), py::arg("data_location")) + .def("AddVariable", &VtuOutput::AddVariable, py::arg("variable"), py::arg("data_location")) + .def("AddIntegrationPointVariable", &VtuOutput::AddIntegrationPointVariable, py::arg("variable"), py::arg("data_location")) + .def("AddIntegrationPointVariable", &VtuOutput::AddIntegrationPointVariable, py::arg("variable"), py::arg("data_location")) + .def("AddIntegrationPointVariable", &VtuOutput::AddIntegrationPointVariable>, py::arg("variable"), py::arg("data_location")) + .def("AddIntegrationPointVariable", &VtuOutput::AddIntegrationPointVariable>, py::arg("variable"), py::arg("data_location")) + .def("AddIntegrationPointVariable", &VtuOutput::AddIntegrationPointVariable>, py::arg("variable"), py::arg("data_location")) + .def("AddIntegrationPointVariable", &VtuOutput::AddIntegrationPointVariable>, py::arg("variable"), py::arg("data_location")) + .def("AddIntegrationPointVariable", &VtuOutput::AddIntegrationPointVariable, py::arg("variable"), py::arg("data_location")) + .def("AddIntegrationPointVariable", &VtuOutput::AddIntegrationPointVariable, py::arg("variable"), py::arg("data_location")) + .def("AddTensorAdaptor", &VtuOutput::AddTensorAdaptor::Pointer>, py::arg("tensor_adaptor_name"), py::arg("tensor_adaptor")) + .def("AddTensorAdaptor", &VtuOutput::AddTensorAdaptor::Pointer>, py::arg("tensor_adaptor_name"), py::arg("tensor_adaptor")) + .def("AddTensorAdaptor", &VtuOutput::AddTensorAdaptor::Pointer>, py::arg("tensor_adaptor_name"), py::arg("tensor_adaptor")) + .def("ReplaceTensorAdaptor", &VtuOutput::ReplaceTensorAdaptor::Pointer>, py::arg("tensor_adaptor_name"), py::arg("tensor_adaptor")) + .def("ReplaceTensorAdaptor", &VtuOutput::ReplaceTensorAdaptor::Pointer>, py::arg("tensor_adaptor_name"), py::arg("tensor_adaptor")) + .def("ReplaceTensorAdaptor", &VtuOutput::ReplaceTensorAdaptor::Pointer>, py::arg("tensor_adaptor_name"), py::arg("tensor_adaptor")) + .def("EmplaceTensorAdaptor", &VtuOutput::EmplaceTensorAdaptor::Pointer>, py::arg("tensor_adaptor_name"), py::arg("tensor_adaptor")) + .def("EmplaceTensorAdaptor", &VtuOutput::EmplaceTensorAdaptor::Pointer>, py::arg("tensor_adaptor_name"), py::arg("tensor_adaptor")) + .def("EmplaceTensorAdaptor", &VtuOutput::EmplaceTensorAdaptor::Pointer>, py::arg("tensor_adaptor_name"), py::arg("tensor_adaptor")) .def("GetModelPart", &VtuOutput::GetModelPart, py::return_value_policy::reference) + .def("GetOutputContainerList", &VtuOutput::GetOutputContainerList) .def("PrintOutput", &VtuOutput::PrintOutput, py::arg("output_file_name_prefix")) + .def("__str__", PrintObject) ; - - vtu_output.attr("NODES") = VtuOutput::NODES; - vtu_output.attr("CONDITIONS") = VtuOutput::CONDITIONS; - vtu_output.attr("ELEMENTS") = VtuOutput::ELEMENTS; } } // namespace Kratos::Python. From d4542bf927bb8a529c6de06516e6f3dc35277ead Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 20 Feb 2026 07:50:42 +0100 Subject: [PATCH 102/116] fix status_stream --- .../builder_and_solvers/p_multigrid/status_stream.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kratos/solving_strategies/builder_and_solvers/p_multigrid/status_stream.cpp b/kratos/solving_strategies/builder_and_solvers/p_multigrid/status_stream.cpp index 53af788cb046..6a2955c6d067 100644 --- a/kratos/solving_strategies/builder_and_solvers/p_multigrid/status_stream.cpp +++ b/kratos/solving_strategies/builder_and_solvers/p_multigrid/status_stream.cpp @@ -42,7 +42,7 @@ using SingleBnS = PMultigridBuilderAndSolver, std::unique_ptr MakeVtuOutput(ModelPart& rModelPart, const PointerVectorSet>& rDofSet) { - auto p_output = std::make_unique(rModelPart); + auto p_output = std::make_unique(rModelPart, Globals::Configuration::Initial); KRATOS_TRY @@ -56,7 +56,7 @@ std::unique_ptr MakeVtuOutput(ModelPart& rModelPart, for (const std::string& r_variable_name : variable_names){ KRATOS_ERROR_IF_NOT(KratosComponents>::Has(r_variable_name)) << r_variable_name << " is not a registered variable name"; - p_output->AddHistoricalVariable(KratosComponents>::Get(r_variable_name)); + p_output->AddVariable(KratosComponents>::Get(r_variable_name), Globals::DataLocation::NodeHistorical); } KRATOS_CATCH("") From 737b73324346145e87ad19d6bcf4ac50a964b959 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 20 Feb 2026 07:51:20 +0100 Subject: [PATCH 103/116] port xml utils from future --- .../xml_appended_data_element_wrapper.cpp | 4 +- .../xml_appended_data_element_wrapper.h | 4 +- .../xml_ascii_nd_data_element.cpp | 4 +- .../xml_utilities/xml_ascii_nd_data_element.h | 4 +- .../xml_base64_binary_nd_data_element.cpp | 4 +- .../xml_base64_binary_nd_data_element.h | 4 +- .../xml_data_element_wrapper.cpp | 4 +- .../xml_utilities/xml_data_element_wrapper.h | 4 +- .../utilities/xml_utilities/xml_element.cpp | 4 +- .../utilities/xml_utilities/xml_element.h | 4 +- .../xml_utilities/xml_elements_array.cpp | 4 +- .../xml_utilities/xml_elements_array.h | 4 +- .../xml_utilities/xml_expression_element.cpp | 141 ------------------ .../xml_utilities/xml_expression_element.h | 131 ---------------- .../xml_in_place_data_element_wrapper.cpp | 4 +- .../xml_in_place_data_element_wrapper.h | 4 +- .../xml_utilities/xml_nd_data_element.cpp | 4 +- .../xml_utilities/xml_nd_data_element.h | 4 +- .../xml_ostream_ascii_writer.cpp | 80 ---------- .../xml_utilities/xml_ostream_ascii_writer.h | 66 -------- .../xml_ostream_base64_binary_writer.cpp | 80 ---------- .../xml_ostream_base64_binary_writer.h | 63 -------- .../xml_utilities/xml_ostream_writer.cpp | 66 -------- .../xml_utilities/xml_ostream_writer.h | 92 ------------ .../utilities/xml_utilities/xml_utils.cpp | 4 +- .../utilities/xml_utilities/xml_utils.h | 4 +- 26 files changed, 36 insertions(+), 755 deletions(-) rename kratos/{future => }/utilities/xml_utilities/xml_appended_data_element_wrapper.cpp (98%) rename kratos/{future => }/utilities/xml_utilities/xml_appended_data_element_wrapper.h (96%) rename kratos/{future => }/utilities/xml_utilities/xml_ascii_nd_data_element.cpp (97%) rename kratos/{future => }/utilities/xml_utilities/xml_ascii_nd_data_element.h (95%) rename kratos/{future => }/utilities/xml_utilities/xml_base64_binary_nd_data_element.cpp (97%) rename kratos/{future => }/utilities/xml_utilities/xml_base64_binary_nd_data_element.h (95%) rename kratos/{future => }/utilities/xml_utilities/xml_data_element_wrapper.cpp (96%) rename kratos/{future => }/utilities/xml_utilities/xml_data_element_wrapper.h (96%) rename kratos/{future => }/utilities/xml_utilities/xml_element.cpp (96%) rename kratos/{future => }/utilities/xml_utilities/xml_element.h (97%) rename kratos/{future => }/utilities/xml_utilities/xml_elements_array.cpp (95%) rename kratos/{future => }/utilities/xml_utilities/xml_elements_array.h (96%) delete mode 100644 kratos/utilities/xml_utilities/xml_expression_element.cpp delete mode 100644 kratos/utilities/xml_utilities/xml_expression_element.h rename kratos/{future => }/utilities/xml_utilities/xml_in_place_data_element_wrapper.cpp (97%) rename kratos/{future => }/utilities/xml_utilities/xml_in_place_data_element_wrapper.h (96%) rename kratos/{future => }/utilities/xml_utilities/xml_nd_data_element.cpp (97%) rename kratos/{future => }/utilities/xml_utilities/xml_nd_data_element.h (94%) delete mode 100644 kratos/utilities/xml_utilities/xml_ostream_ascii_writer.cpp delete mode 100644 kratos/utilities/xml_utilities/xml_ostream_ascii_writer.h delete mode 100644 kratos/utilities/xml_utilities/xml_ostream_base64_binary_writer.cpp delete mode 100644 kratos/utilities/xml_utilities/xml_ostream_base64_binary_writer.h delete mode 100644 kratos/utilities/xml_utilities/xml_ostream_writer.cpp delete mode 100644 kratos/utilities/xml_utilities/xml_ostream_writer.h rename kratos/{future => }/utilities/xml_utilities/xml_utils.cpp (97%) rename kratos/{future => }/utilities/xml_utilities/xml_utils.h (97%) diff --git a/kratos/future/utilities/xml_utilities/xml_appended_data_element_wrapper.cpp b/kratos/utilities/xml_utilities/xml_appended_data_element_wrapper.cpp similarity index 98% rename from kratos/future/utilities/xml_utilities/xml_appended_data_element_wrapper.cpp rename to kratos/utilities/xml_utilities/xml_appended_data_element_wrapper.cpp index ee8afacfd8c7..cf731a4362b3 100644 --- a/kratos/future/utilities/xml_utilities/xml_appended_data_element_wrapper.cpp +++ b/kratos/utilities/xml_utilities/xml_appended_data_element_wrapper.cpp @@ -23,7 +23,7 @@ // Include base h #include "xml_appended_data_element_wrapper.h" -namespace Kratos::Future { +namespace Kratos { XmlAppendedDataElementWrapper::XmlAppendedDataElementWrapper(const XmlOutputType OutputType) : BaseType("AppendedData"), @@ -136,4 +136,4 @@ void XmlAppendedDataElementWrapper::Write( KRATOS_CATCH(""); } -} // namespace Kratos::Future \ No newline at end of file +} // namespace Kratos \ No newline at end of file diff --git a/kratos/future/utilities/xml_utilities/xml_appended_data_element_wrapper.h b/kratos/utilities/xml_utilities/xml_appended_data_element_wrapper.h similarity index 96% rename from kratos/future/utilities/xml_utilities/xml_appended_data_element_wrapper.h rename to kratos/utilities/xml_utilities/xml_appended_data_element_wrapper.h index 9ffe3e56889c..499379ab152c 100644 --- a/kratos/future/utilities/xml_utilities/xml_appended_data_element_wrapper.h +++ b/kratos/utilities/xml_utilities/xml_appended_data_element_wrapper.h @@ -19,7 +19,7 @@ #include "containers/nd_data.h" #include "xml_data_element_wrapper.h" -namespace Kratos::Future { +namespace Kratos { ///@name Kratos Classes ///@{ @@ -82,4 +82,4 @@ class KRATOS_API(KRATOS_CORE) XmlAppendedDataElementWrapper : public XmlDataElem ///@} }; -} // namespace Kratos::Future \ No newline at end of file +} // namespace Kratos \ No newline at end of file diff --git a/kratos/future/utilities/xml_utilities/xml_ascii_nd_data_element.cpp b/kratos/utilities/xml_utilities/xml_ascii_nd_data_element.cpp similarity index 97% rename from kratos/future/utilities/xml_utilities/xml_ascii_nd_data_element.cpp rename to kratos/utilities/xml_utilities/xml_ascii_nd_data_element.cpp index f03643be5400..3d938d7a66f2 100644 --- a/kratos/future/utilities/xml_utilities/xml_ascii_nd_data_element.cpp +++ b/kratos/utilities/xml_utilities/xml_ascii_nd_data_element.cpp @@ -20,7 +20,7 @@ // Include base h #include "xml_ascii_nd_data_element.h" -namespace Kratos::Future { +namespace Kratos { ///@name Kratos Classes ///@{ @@ -79,4 +79,4 @@ template class XmlAsciiNDDataElement; template class XmlAsciiNDDataElement; template class XmlAsciiNDDataElement; -} // namespace Kratos::Future +} // namespace Kratos diff --git a/kratos/future/utilities/xml_utilities/xml_ascii_nd_data_element.h b/kratos/utilities/xml_utilities/xml_ascii_nd_data_element.h similarity index 95% rename from kratos/future/utilities/xml_utilities/xml_ascii_nd_data_element.h rename to kratos/utilities/xml_utilities/xml_ascii_nd_data_element.h index f6c760c2ca1b..b92e5e28a14d 100644 --- a/kratos/future/utilities/xml_utilities/xml_ascii_nd_data_element.h +++ b/kratos/utilities/xml_utilities/xml_ascii_nd_data_element.h @@ -20,7 +20,7 @@ #include "containers/nd_data.h" #include "xml_nd_data_element.h" -namespace Kratos::Future { +namespace Kratos { ///@name Kratos Classes ///@{ @@ -67,4 +67,4 @@ class KRATOS_API(KRATOS_CORE) XmlAsciiNDDataElement : public XmlNDDataElement; template class XmlBase64BinaryNDDataElement; template class XmlBase64BinaryNDDataElement; -} // namespace Kratos::Future +} // namespace Kratos diff --git a/kratos/future/utilities/xml_utilities/xml_base64_binary_nd_data_element.h b/kratos/utilities/xml_utilities/xml_base64_binary_nd_data_element.h similarity index 95% rename from kratos/future/utilities/xml_utilities/xml_base64_binary_nd_data_element.h rename to kratos/utilities/xml_utilities/xml_base64_binary_nd_data_element.h index 54cfe3f3b585..9c9ec066477e 100644 --- a/kratos/future/utilities/xml_utilities/xml_base64_binary_nd_data_element.h +++ b/kratos/utilities/xml_utilities/xml_base64_binary_nd_data_element.h @@ -20,7 +20,7 @@ #include "containers/nd_data.h" #include "xml_nd_data_element.h" -namespace Kratos::Future { +namespace Kratos { ///@name Kratos Classes ///@{ @@ -59,4 +59,4 @@ class KRATOS_API(KRATOS_CORE) XmlBase64BinaryNDDataElement : public XmlNDDataEle ///@} -} // namespace Kratos::Future +} // namespace Kratos diff --git a/kratos/future/utilities/xml_utilities/xml_data_element_wrapper.cpp b/kratos/utilities/xml_utilities/xml_data_element_wrapper.cpp similarity index 96% rename from kratos/future/utilities/xml_utilities/xml_data_element_wrapper.cpp rename to kratos/utilities/xml_utilities/xml_data_element_wrapper.cpp index 7a7f35613d59..088cba6d585f 100644 --- a/kratos/future/utilities/xml_utilities/xml_data_element_wrapper.cpp +++ b/kratos/utilities/xml_utilities/xml_data_element_wrapper.cpp @@ -20,7 +20,7 @@ // Include base h #include "xml_data_element_wrapper.h" -namespace Kratos::Future { +namespace Kratos { XmlDataElementWrapper::XmlDataElementWrapper(const std::string& rTagName) : XmlElement(rTagName) @@ -54,4 +54,4 @@ XmlElement::Pointer XmlDataElementWrapper::Get( KRATOS_CATCH(""); } -} // namespace Kratos::Future \ No newline at end of file +} // namespace Kratos \ No newline at end of file diff --git a/kratos/future/utilities/xml_utilities/xml_data_element_wrapper.h b/kratos/utilities/xml_utilities/xml_data_element_wrapper.h similarity index 96% rename from kratos/future/utilities/xml_utilities/xml_data_element_wrapper.h rename to kratos/utilities/xml_utilities/xml_data_element_wrapper.h index 777465be8f94..84d57227fd2e 100644 --- a/kratos/future/utilities/xml_utilities/xml_data_element_wrapper.h +++ b/kratos/utilities/xml_utilities/xml_data_element_wrapper.h @@ -20,7 +20,7 @@ #include "containers/nd_data.h" #include "xml_element.h" -namespace Kratos::Future { +namespace Kratos { ///@name Kratos Classes ///@{ @@ -64,4 +64,4 @@ class KRATOS_API(KRATOS_CORE) XmlDataElementWrapper : public XmlElement ///@} }; -} // namespace Kratos::Future \ No newline at end of file +} // namespace Kratos \ No newline at end of file diff --git a/kratos/future/utilities/xml_utilities/xml_element.cpp b/kratos/utilities/xml_utilities/xml_element.cpp similarity index 96% rename from kratos/future/utilities/xml_utilities/xml_element.cpp rename to kratos/utilities/xml_utilities/xml_element.cpp index 9aafcfac9c4c..45329948ede9 100644 --- a/kratos/future/utilities/xml_utilities/xml_element.cpp +++ b/kratos/utilities/xml_utilities/xml_element.cpp @@ -17,7 +17,7 @@ // Include base h #include "xml_element.h" -namespace Kratos::Future { +namespace Kratos { XmlElement::XmlElement(const std::string& rTagName) : mTagName(rTagName) @@ -83,4 +83,4 @@ void XmlElement::WriteEmptyElementTag( rOStream << "/>\n"; } -} // namespace Kratos::Future \ No newline at end of file +} // namespace Kratos \ No newline at end of file diff --git a/kratos/future/utilities/xml_utilities/xml_element.h b/kratos/utilities/xml_utilities/xml_element.h similarity index 97% rename from kratos/future/utilities/xml_utilities/xml_element.h rename to kratos/utilities/xml_utilities/xml_element.h index 104f499cf5f3..6dc6dd86d8aa 100644 --- a/kratos/future/utilities/xml_utilities/xml_element.h +++ b/kratos/utilities/xml_utilities/xml_element.h @@ -19,7 +19,7 @@ // Project includes #include "includes/define.h" -namespace Kratos::Future { +namespace Kratos { ///@name Kratos Classes ///@{ @@ -101,4 +101,4 @@ class KRATOS_API(KRATOS_CORE) XmlElement ///@} }; -} // namespace Kratos::Future \ No newline at end of file +} // namespace Kratos \ No newline at end of file diff --git a/kratos/future/utilities/xml_utilities/xml_elements_array.cpp b/kratos/utilities/xml_utilities/xml_elements_array.cpp similarity index 95% rename from kratos/future/utilities/xml_utilities/xml_elements_array.cpp rename to kratos/utilities/xml_utilities/xml_elements_array.cpp index f2007c1eacc1..9885fd077917 100644 --- a/kratos/future/utilities/xml_utilities/xml_elements_array.cpp +++ b/kratos/utilities/xml_utilities/xml_elements_array.cpp @@ -17,7 +17,7 @@ // Include base h #include "xml_elements_array.h" -namespace Kratos::Future { +namespace Kratos { XmlElementsArray::XmlElementsArray(const std::string& rTagName) : BaseType(rTagName) @@ -60,4 +60,4 @@ void XmlElementsArray:: Write( KRATOS_CATCH(""); } -} // namespace Kratos::Future \ No newline at end of file +} // namespace Kratos \ No newline at end of file diff --git a/kratos/future/utilities/xml_utilities/xml_elements_array.h b/kratos/utilities/xml_utilities/xml_elements_array.h similarity index 96% rename from kratos/future/utilities/xml_utilities/xml_elements_array.h rename to kratos/utilities/xml_utilities/xml_elements_array.h index 65cb97b0d513..29634ae2ad4f 100644 --- a/kratos/future/utilities/xml_utilities/xml_elements_array.h +++ b/kratos/utilities/xml_utilities/xml_elements_array.h @@ -20,7 +20,7 @@ #include "includes/define.h" #include "xml_element.h" -namespace Kratos::Future { +namespace Kratos { ///@name Kratos Classes ///@{ @@ -78,4 +78,4 @@ class KRATOS_API(KRATOS_CORE) XmlElementsArray : public XmlElement ///@} }; -} // namespace Kratos::Future \ No newline at end of file +} // namespace Kratos \ No newline at end of file diff --git a/kratos/utilities/xml_utilities/xml_expression_element.cpp b/kratos/utilities/xml_utilities/xml_expression_element.cpp deleted file mode 100644 index e0248977bbb0..000000000000 --- a/kratos/utilities/xml_utilities/xml_expression_element.cpp +++ /dev/null @@ -1,141 +0,0 @@ -// | / | -// ' / __| _` | __| _ \ __| -// . \ | ( | | ( |\__ ` -// _|\_\_| \__,_|\__|\___/ ____/ -// Multi-Physics -// -// License: BSD License -// Kratos default license: kratos/license.txt -// -// Main authors: Suneth Warnakulasuriya -// - -// System includes - -// Project includes -#include "expression/literal_flat_expression.h" - -// Include base h -#include "xml_expression_element.h" - -namespace Kratos { - -XmlExpressionElement::XmlExpressionElement(const std::string& rTagName) - : mTagName(rTagName) -{ -} - -XmlExpressionElement::XmlExpressionElement( - const std::string& rDataName, - const std::vector& rExpressions) - : mTagName("DataArray"), - mExpressions(rExpressions) -{ - KRATOS_ERROR_IF(rExpressions.size() == 0) - << "Empty expression lists are not allowed."; - - IndexType number_of_components = 0; - - for (const auto& p_expression : rExpressions) { - if (number_of_components == 0) { - number_of_components = p_expression->GetItemComponentCount(); - } - KRATOS_ERROR_IF(number_of_components != p_expression->GetItemComponentCount()) - << "Found expressions with mismatching shapes."; - } - - if (std::all_of(mExpressions.begin(), mExpressions.end(), [](const auto& pExpression) { - return dynamic_cast*>(&*pExpression); - })) { - AddAttribute("type", "UInt" + std::to_string(sizeof(char) * 8)); - } else if (std::all_of(mExpressions.begin(), mExpressions.end(), [](const auto& pExpression) { - return dynamic_cast*>(&*pExpression); - })) { - AddAttribute("type", "Int" + std::to_string(sizeof(int) * 8)); - } else { - AddAttribute("type", "Float" + std::to_string(sizeof(double) * 8)); - } - - AddAttribute("Name", rDataName); - - if (number_of_components > 0) { - AddAttribute("NumberOfComponents", std::to_string(number_of_components)); - } -} - - ///@} - ///@name Public operations - ///@{ - -const std::string XmlExpressionElement::GetTagName() const -{ - return mTagName; -}; - -void XmlExpressionElement::AddAttribute( - const std::string& rName, - const std::string& rValue) -{ - for (const auto& r_attribute : mAttributes) { - KRATOS_ERROR_IF(r_attribute.first == rName) - << "There exists an attribute named \"" << rName - << "\" in the xml element with value = \"" - << r_attribute.second << "\" [ given new value = \"" - << rValue << "\" ].\n"; - } - mAttributes.push_back(std::make_pair(rName, rValue)); -} - -const std::vector>& XmlExpressionElement::GetAttributes() const -{ - return mAttributes; -} - -void XmlExpressionElement::ClearAttributes() -{ - mAttributes.clear(); -} - -void XmlExpressionElement::AddElement(const XmlExpressionElement::Pointer pXmlElement) -{ - if (mExpressions.size() == 0) { - for (const auto& p_element : mXmlElements) { - KRATOS_ERROR_IF(&*(p_element) == &*(pXmlElement)) - << "The xml element is already aded."; - } - mXmlElements.push_back(pXmlElement); - } else { - KRATOS_ERROR << "Cannot add element to an Xml element which has " - "data [ current xml tag = \"" - << GetTagName() << "\", new element tag name = \"" - << pXmlElement->GetTagName() << "\" ].\n"; - } -} - -std::vector XmlExpressionElement::GetElements(const std::string& rTagName) const -{ - std::vector results; - for (const auto& p_element : mXmlElements) { - if (p_element->GetTagName() == rTagName) { - results.push_back(p_element); - } - } - return results; -} - -const std::vector& XmlExpressionElement::GetElements() const -{ - return mXmlElements; -} - -void XmlExpressionElement::ClearElements() -{ - mXmlElements.clear(); -} - -const std::vector XmlExpressionElement::GetExpressions() const -{ - return mExpressions; -} - -} // namespace Kratos diff --git a/kratos/utilities/xml_utilities/xml_expression_element.h b/kratos/utilities/xml_utilities/xml_expression_element.h deleted file mode 100644 index eb2d3f7644bb..000000000000 --- a/kratos/utilities/xml_utilities/xml_expression_element.h +++ /dev/null @@ -1,131 +0,0 @@ -// | / | -// ' / __| _` | __| _ \ __| -// . \ | ( | | ( |\__ ` -// _|\_\_| \__,_|\__|\___/ ____/ -// Multi-Physics -// -// License: BSD License -// Kratos default license: kratos/license.txt -// -// Main authors: Suneth Warnakulasuriya -// - -#pragma once - -// System includes -#include -#include - -// Project includes -#include "includes/define.h" -#include "expression/expression.h" - -namespace Kratos { - -///@name Kratos Classes -///@{ - -class KRATOS_API(KRATOS_CORE) XmlExpressionElement { -public: - ///@name Type definitions - ///@{ - - using IndexType = std::size_t; - - KRATOS_CLASS_POINTER_DEFINITION(XmlExpressionElement); - - ///@} - ///@name Life cycle - ///@{ - - /** - * @brief Constructor. - * @param rTagName The tag name of the XML element. - */ - XmlExpressionElement(const std::string& rTagName); - - /** - * @brief Constructor. - * @param rDataName The name of the data element. - * @param rExpressions The expressions to write as data. - */ - XmlExpressionElement( - const std::string& rDataName, - const std::vector& rExpressions); - - ///@} - ///@name Public operations - ///@{ - - /** - * @brief Get the tag name of the XML element. - * @return The tag name. - */ - const std::string GetTagName() const; - - /** - * @brief Add an attribute to the XML element. - * @param rName The name of the attribute. - * @param rValue The value of the attribute. - */ - void AddAttribute( - const std::string& rName, - const std::string& rValue); - - /** - * @brief Get the attributes of the XML element. - * @return The attributes. - */ - const std::vector>& GetAttributes() const; - - /** - * @brief Clear the attributes of the XML element. - */ - void ClearAttributes(); - - /** - * @brief Add a sub-element to the XML element. - * @param pXmlElement The sub-element to add. - */ - void AddElement(const XmlExpressionElement::Pointer pXmlElement); - - /** - * @brief Get sub-elements with a specific tag name. - * @param rTagName The tag name of the sub-elements. - * @return The vector of sub-elements. - */ - std::vector GetElements(const std::string& rTagName) const; - - /** - * @brief Get all sub-elements of the XML element. - * @return The vector of sub-elements. - */ - const std::vector& GetElements() const; - - /** - * @brief Clear all sub-elements of the XML element. - */ - void ClearElements(); - - const std::vector GetExpressions() const; - - ///@} - -private: - ///@name Private member variables - ///@{ - - const std::string mTagName; /// The tag name of the XML element. - - std::vector> mAttributes; /// The attributes of the XML element. - - std::vector mXmlElements; /// The sub-elements of the XML element. - - const std::vector mExpressions; /// The expressions to write as data. - - ///@} -}; - -///@} - -} // namespace Kratos diff --git a/kratos/future/utilities/xml_utilities/xml_in_place_data_element_wrapper.cpp b/kratos/utilities/xml_utilities/xml_in_place_data_element_wrapper.cpp similarity index 97% rename from kratos/future/utilities/xml_utilities/xml_in_place_data_element_wrapper.cpp rename to kratos/utilities/xml_utilities/xml_in_place_data_element_wrapper.cpp index 931509fd88f5..376ad2693113 100644 --- a/kratos/future/utilities/xml_utilities/xml_in_place_data_element_wrapper.cpp +++ b/kratos/utilities/xml_utilities/xml_in_place_data_element_wrapper.cpp @@ -24,7 +24,7 @@ // Include base h #include "xml_in_place_data_element_wrapper.h" -namespace Kratos::Future { +namespace Kratos { XmlInPlaceDataElementWrapper::XmlInPlaceDataElementWrapper( const XmlOutputType OutputType, @@ -74,4 +74,4 @@ void XmlInPlaceDataElementWrapper::Write( KRATOS_CATCH(""); } -} // namespace Kratos::Future \ No newline at end of file +} // namespace Kratos \ No newline at end of file diff --git a/kratos/future/utilities/xml_utilities/xml_in_place_data_element_wrapper.h b/kratos/utilities/xml_utilities/xml_in_place_data_element_wrapper.h similarity index 96% rename from kratos/future/utilities/xml_utilities/xml_in_place_data_element_wrapper.h rename to kratos/utilities/xml_utilities/xml_in_place_data_element_wrapper.h index 53348b65c686..fcf125ed2622 100644 --- a/kratos/future/utilities/xml_utilities/xml_in_place_data_element_wrapper.h +++ b/kratos/utilities/xml_utilities/xml_in_place_data_element_wrapper.h @@ -19,7 +19,7 @@ #include "containers/nd_data.h" #include "xml_data_element_wrapper.h" -namespace Kratos::Future { +namespace Kratos { ///@name Kratos Classes ///@{ @@ -84,4 +84,4 @@ class KRATOS_API(KRATOS_CORE) XmlInPlaceDataElementWrapper : public XmlDataEleme ///@} }; -} // namespace Kratos::Future \ No newline at end of file +} // namespace Kratos \ No newline at end of file diff --git a/kratos/future/utilities/xml_utilities/xml_nd_data_element.cpp b/kratos/utilities/xml_utilities/xml_nd_data_element.cpp similarity index 97% rename from kratos/future/utilities/xml_utilities/xml_nd_data_element.cpp rename to kratos/utilities/xml_utilities/xml_nd_data_element.cpp index 56fa0755897e..2705e23c8ce6 100644 --- a/kratos/future/utilities/xml_utilities/xml_nd_data_element.cpp +++ b/kratos/utilities/xml_utilities/xml_nd_data_element.cpp @@ -20,7 +20,7 @@ // Include base h #include "xml_nd_data_element.h" -namespace Kratos::Future { +namespace Kratos { ///@name Kratos Classes ///@{ @@ -66,4 +66,4 @@ template class XmlNDDataElement; template class XmlNDDataElement; template class XmlNDDataElement; -} // namespace Kratos::Future +} // namespace Kratos diff --git a/kratos/future/utilities/xml_utilities/xml_nd_data_element.h b/kratos/utilities/xml_utilities/xml_nd_data_element.h similarity index 94% rename from kratos/future/utilities/xml_utilities/xml_nd_data_element.h rename to kratos/utilities/xml_utilities/xml_nd_data_element.h index 223700ce8c10..177d1d951951 100644 --- a/kratos/future/utilities/xml_utilities/xml_nd_data_element.h +++ b/kratos/utilities/xml_utilities/xml_nd_data_element.h @@ -20,7 +20,7 @@ #include "containers/nd_data.h" #include "xml_element.h" -namespace Kratos::Future { +namespace Kratos { ///@name Kratos Classes ///@{ @@ -56,4 +56,4 @@ class KRATOS_API(KRATOS_CORE) XmlNDDataElement : public XmlElement { ///@} -} // namespace Kratos::Future +} // namespace Kratos diff --git a/kratos/utilities/xml_utilities/xml_ostream_ascii_writer.cpp b/kratos/utilities/xml_utilities/xml_ostream_ascii_writer.cpp deleted file mode 100644 index 9e002703e4e0..000000000000 --- a/kratos/utilities/xml_utilities/xml_ostream_ascii_writer.cpp +++ /dev/null @@ -1,80 +0,0 @@ -// | / | -// ' / __| _` | __| _ \ __| -// . \ | ( | | ( |\__ ` -// _|\_\_| \__,_|\__|\___/ ____/ -// Multi-Physics -// -// License: BSD License -// Kratos default license: kratos/license.txt -// -// Main authors: Suneth Warnakulasuriya -// - -// System includes -#include -#include -#include -#include - -// Project includes -#include "expression/literal_flat_expression.h" - -// Include base h -#include "xml_ostream_ascii_writer.h" - -namespace Kratos { - -namespace XmlOStreamAsciiWriterHelperUtilities -{ -template -void WriteExpression( - std::ostream& rOStream, - const std::vector& rExpressions) -{ - std::vector transformed_expressions(rExpressions.size()); - std::transform(rExpressions.begin(), rExpressions.end(), - transformed_expressions.begin(), [](auto& pExpression) { - return dynamic_cast(&*(pExpression)); - }); - - for (const auto& p_expression : transformed_expressions) { - auto itr = p_expression->cbegin(); - auto data_end = p_expression->cend(); - for (; itr != data_end; ++itr) { - if constexpr (std::is_same_v, const char>) { - rOStream << " " << static_cast(*(itr)); - } - else { - rOStream << " " << *itr; - } - } - } -} -} // namespace XmlOStreamAsciiWriterHelperUtilities - -XmlOStreamAsciiWriter::XmlOStreamAsciiWriter( - std::ostream& rOStream, - const IndexType Precision) - : XmlOStreamWriter(rOStream) -{ - mrOStream << std::scientific << std::setprecision(Precision); -} - -void XmlOStreamAsciiWriter::WriteExpressions( - const std::vector& rExpressions, - const std::string& rTabbing) -{ - mrOStream << " format=\"ascii\">\n" << rTabbing; - - if (std::all_of(rExpressions.begin(), rExpressions.end(), [](const auto& pExpression) { return dynamic_cast*>(&*pExpression); })) { - XmlOStreamAsciiWriterHelperUtilities::WriteExpression>(mrOStream, rExpressions); - } else if (std::all_of(rExpressions.begin(), rExpressions.end(), [](const auto& pExpression) { return dynamic_cast*>(&*pExpression); })) { - XmlOStreamAsciiWriterHelperUtilities::WriteExpression>(mrOStream, rExpressions); - } else if (std::all_of(rExpressions.begin(), rExpressions.end(), [](const auto& pExpression) { return dynamic_cast*>(&*pExpression); })) { - XmlOStreamAsciiWriterHelperUtilities::WriteExpression>(mrOStream, rExpressions); - } else { - XmlOStreamAsciiWriterHelperUtilities::WriteExpression(mrOStream, rExpressions); - } -} - -} // namespace Kratos \ No newline at end of file diff --git a/kratos/utilities/xml_utilities/xml_ostream_ascii_writer.h b/kratos/utilities/xml_utilities/xml_ostream_ascii_writer.h deleted file mode 100644 index 1f0b31885e05..000000000000 --- a/kratos/utilities/xml_utilities/xml_ostream_ascii_writer.h +++ /dev/null @@ -1,66 +0,0 @@ -// | / | -// ' / __| _` | __| _ \ __| -// . \ | ( | | ( |\__ ` -// _|\_\_| \__,_|\__|\___/ ____/ -// Multi-Physics -// -// License: BSD License -// Kratos default license: kratos/license.txt -// -// Main authors: Suneth Warnakulasuriya -// - -#pragma once - -// System includes -#include - -// Project includes -#include "includes/define.h" -#include "xml_ostream_writer.h" - -namespace Kratos { - -///@name Kratos Classes -///@{ - -/* @class XmlOStreamAsciiWriter - * @ingroup KratosCore - * @brief Output stream ascii writer for XML format. - * @author Suneth Warnakulasuriya - */ -class KRATOS_API(KRATOS_CORE) XmlOStreamAsciiWriter: public XmlOStreamWriter -{ -public: - ///@name Life cycle - ///@{ - - using IndexType = std::size_t; - - ///@} - ///@name Life cycle - ///@{ - - /** - * @brief Constructor. - * @param rOStream The output stream to write to. - * @param Precision The precision for floating-point numbers. - */ - XmlOStreamAsciiWriter( - std::ostream& rOStream, - const IndexType Precision); - - ///@} - -protected: - ///@name Protected operations - ///@{ - - void WriteExpressions( - const std::vector& rExpressions, - const std::string& rTabbing) override; - - ///@} -}; - -} // namespace Kratos \ No newline at end of file diff --git a/kratos/utilities/xml_utilities/xml_ostream_base64_binary_writer.cpp b/kratos/utilities/xml_utilities/xml_ostream_base64_binary_writer.cpp deleted file mode 100644 index 51a21c5e2e58..000000000000 --- a/kratos/utilities/xml_utilities/xml_ostream_base64_binary_writer.cpp +++ /dev/null @@ -1,80 +0,0 @@ -// | / | -// ' / __| _` | __| _ \ __| -// . \ | ( | | ( |\__ ` -// _|\_\_| \__,_|\__|\___/ ____/ -// Multi-Physics -// -// License: BSD License -// Kratos default license: kratos/license.txt -// -// Main authors: Suneth Warnakulasuriya -// - -// System includes -#include -#include -#include -#include - -// Project includes -#include "input_output/base_64_encoded_output.h" -#include "expression/literal_flat_expression.h" - -// Include base h -#include "xml_ostream_base64_binary_writer.h" - -namespace Kratos { - -namespace XmlOStreamBase64BinaryWriterHelperUtilities -{ -template -void WriteExpression( - std::ostream& rOStream, - const std::vector& rExpressions) -{ - std::vector transformed_expressions(rExpressions.size()); - std::transform(rExpressions.begin(), rExpressions.end(), - transformed_expressions.begin(), [](auto& pExpression) { - return dynamic_cast(&*(pExpression)); - }); - - constexpr std::size_t data_type_size = sizeof(decltype(*(transformed_expressions[0]->cbegin()))); - const std::size_t total_entities = std::accumulate(rExpressions.begin(), rExpressions.end(), 0U, [](const std::size_t LHS, const auto& pExpression) { return LHS + pExpression->NumberOfEntities();}); - const std::size_t flattened_shape_size = rExpressions[0]->GetItemComponentCount(); - const std::size_t total_number_of_values = total_entities * flattened_shape_size; - const unsigned int total_data_size = total_number_of_values * data_type_size; - - { - Base64EncodedOutput base64_encoder(rOStream); - - base64_encoder.WriteData(&total_data_size, 1); - for (const auto p_expression : transformed_expressions) { - base64_encoder.WriteData(p_expression->cbegin(), p_expression->NumberOfEntities() * flattened_shape_size); - } - } -} -} // namespace XmlOStreamBase64BinaryWriterHelperUtilities - -XmlOStreamBase64BinaryWriter::XmlOStreamBase64BinaryWriter(std::ostream& rOStream) - : XmlOStreamWriter(rOStream) -{ -} - -void XmlOStreamBase64BinaryWriter::WriteExpressions( - const std::vector& rExpressions, - const std::string& rTabbing) -{ - mrOStream << " format=\"binary\">\n" << rTabbing << " "; - - if (std::all_of(rExpressions.begin(), rExpressions.end(), [](const auto& pExpression) { return dynamic_cast*>(&*pExpression); })) { - XmlOStreamBase64BinaryWriterHelperUtilities::WriteExpression>(mrOStream, rExpressions); - } else if (std::all_of(rExpressions.begin(), rExpressions.end(), [](const auto& pExpression) { return dynamic_cast*>(&*pExpression); })) { - XmlOStreamBase64BinaryWriterHelperUtilities::WriteExpression>(mrOStream, rExpressions); - } else if (std::all_of(rExpressions.begin(), rExpressions.end(), [](const auto& pExpression) { return dynamic_cast*>(&*pExpression); })) { - XmlOStreamBase64BinaryWriterHelperUtilities::WriteExpression>(mrOStream, rExpressions); - } else { - XmlOStreamBase64BinaryWriterHelperUtilities::WriteExpression(mrOStream, rExpressions); - } -} - -} // namespace Kratos \ No newline at end of file diff --git a/kratos/utilities/xml_utilities/xml_ostream_base64_binary_writer.h b/kratos/utilities/xml_utilities/xml_ostream_base64_binary_writer.h deleted file mode 100644 index 62dddd5d6947..000000000000 --- a/kratos/utilities/xml_utilities/xml_ostream_base64_binary_writer.h +++ /dev/null @@ -1,63 +0,0 @@ -// | / | -// ' / __| _` | __| _ \ __| -// . \ | ( | | ( |\__ ` -// _|\_\_| \__,_|\__|\___/ ____/ -// Multi-Physics -// -// License: BSD License -// Kratos default license: kratos/license.txt -// -// Main authors: Suneth Warnakulasuriya -// - -#pragma once - -// System includes -#include - -// Project includes -#include "includes/define.h" -#include "xml_ostream_writer.h" - -namespace Kratos { - -///@name Kratos Classes -///@{ - -/* @class XmlOStreamBase64BinaryWriter - * @ingroup KratosCore - * @brief Output stream ascii writer for XML format. - * @author Suneth Warnakulasuriya - */ -class KRATOS_API(KRATOS_CORE) XmlOStreamBase64BinaryWriter: public XmlOStreamWriter -{ -public: - ///@name Life cycle - ///@{ - - using IndexType = std::size_t; - - ///@} - ///@name Life cycle - ///@{ - - /** - * @brief Constructor. - * @param rOStream The output stream to write to. - */ - XmlOStreamBase64BinaryWriter(std::ostream& rOStream); - - ///@} - -protected: - ///@name Protected operations - ///@{ - - void WriteExpressions( - const std::vector& rExpressions, - const std::string& rTabbing) override; - - ///@} -}; - -} // namespace Kratos \ No newline at end of file diff --git a/kratos/utilities/xml_utilities/xml_ostream_writer.cpp b/kratos/utilities/xml_utilities/xml_ostream_writer.cpp deleted file mode 100644 index 9b393fdf7800..000000000000 --- a/kratos/utilities/xml_utilities/xml_ostream_writer.cpp +++ /dev/null @@ -1,66 +0,0 @@ -// | / | -// ' / __| _` | __| _ \ __| -// . \ | ( | | ( |\__ ` -// _|\_\_| \__,_|\__|\___/ ____/ -// Multi-Physics -// -// License: BSD License -// Kratos default license: kratos/license.txt -// -// Main authors: Suneth Warnakulasuriya -// - -// System includes -#include -#include -#include - -// Project includes -#include "expression/literal_flat_expression.h" - -// Include base h -#include "xml_ostream_writer.h" - -namespace Kratos { - -XmlOStreamWriter::XmlOStreamWriter(std::ostream& rOStream) - : mrOStream(rOStream) -{ -} - -void XmlOStreamWriter::WriteElement( - const XmlExpressionElement& rElement, - const IndexType Level) -{ - const std::string tabbing(Level * 3, ' '); - - mrOStream << tabbing << "<" << rElement.GetTagName(); - const auto& r_attributes = rElement.GetAttributes(); - if (r_attributes.size() > 0) { - for (const auto& r_pair : r_attributes) { - mrOStream << " " << r_pair.first << "=\"" << r_pair.second << "\""; - } - } - - const auto& r_sub_elements = rElement.GetElements(); - const auto& r_expressions = rElement.GetExpressions(); - - if (r_sub_elements.size() > 0) { - // write sub elements - mrOStream << ">\n"; - for (const auto& p_sub_element : r_sub_elements) { - this->WriteElement(*p_sub_element, Level + 1); - } - mrOStream << tabbing << "\n"; - } else if (r_expressions.size() > 0) { - // write a data expression element - this->WriteExpressions(r_expressions, tabbing); - // close the element - mrOStream << "\n" << tabbing << "\n"; - } else { - // then it is an empty element. - mrOStream << "/>\n"; - } -} - -} // namespace Kratos \ No newline at end of file diff --git a/kratos/utilities/xml_utilities/xml_ostream_writer.h b/kratos/utilities/xml_utilities/xml_ostream_writer.h deleted file mode 100644 index 51060ea11a5a..000000000000 --- a/kratos/utilities/xml_utilities/xml_ostream_writer.h +++ /dev/null @@ -1,92 +0,0 @@ -// | / | -// ' / __| _` | __| _ \ __| -// . \ | ( | | ( |\__ ` -// _|\_\_| \__,_|\__|\___/ ____/ -// Multi-Physics -// -// License: BSD License -// Kratos default license: kratos/license.txt -// -// Main authors: Suneth Warnakulasuriya -// - -#pragma once - -// System includes -#include -#include - -// Project includes -#include "includes/define.h" -#include "expression/literal_flat_expression.h" -#include "utilities/xml_utilities/xml_expression_element.h" - -namespace Kratos { - -///@name Kratos Classes -///@{ - -/* @class XmlOStreamWriter - * @ingroup KratosCore - * @brief Output stream writer for XML format. - * @author Suneth Warnakulasuriya - */ -class KRATOS_API(KRATOS_CORE) XmlOStreamWriter -{ -public: - ///@name Life cycle - ///@{ - - using IndexType = std::size_t; - - ///@} - ///@name Life cycle - ///@{ - - /** - * @brief Constructor. - * @param rOStream The output stream to write to. - */ - XmlOStreamWriter(std::ostream& rOStream); - - virtual ~XmlOStreamWriter() = default; - - ///@} - ///@name Public operations - ///@{ - - /** - * @brief Writes an XML expression element. - * @param XmlExpressionElement Expression xml element to be written. - * @param Level The indentation level. - */ - void WriteElement( - const XmlExpressionElement& rElement, - const IndexType Level = 0); - - ///@} - -protected: - ///@name Protected member variables - ///@{ - - std::ostream& mrOStream; /// The output stream - - ///@} - ///@name Protected operations - ///@{ - - /** - * @brief Writes generic lazy type expressions - * - * @param rExpressions Expressions list to write. - * @param rTabbing Tabbing used for expression writing. - */ - virtual void WriteExpressions( - const std::vector& rExpressions, - const std::string& rTabbing) = 0; - - ///@} -}; - -} // namespace Kratos \ No newline at end of file diff --git a/kratos/future/utilities/xml_utilities/xml_utils.cpp b/kratos/utilities/xml_utilities/xml_utils.cpp similarity index 97% rename from kratos/future/utilities/xml_utilities/xml_utils.cpp rename to kratos/utilities/xml_utilities/xml_utils.cpp index 263e1be172de..80d594159e84 100644 --- a/kratos/future/utilities/xml_utilities/xml_utils.cpp +++ b/kratos/utilities/xml_utilities/xml_utils.cpp @@ -18,7 +18,7 @@ // Include base h #include "xml_utils.h" -namespace Kratos::Future { +namespace Kratos { template void XmlUtilities::AddDataArrayAttributes( @@ -56,4 +56,4 @@ template void XmlUtilities::AddDataArrayAttributes(XmlElement&, const NDData&); template void XmlUtilities::AddDataArrayAttributes(XmlElement&, const NDData&); -} // namespace Kratos::Future \ No newline at end of file +} // namespace Kratos \ No newline at end of file diff --git a/kratos/future/utilities/xml_utilities/xml_utils.h b/kratos/utilities/xml_utilities/xml_utils.h similarity index 97% rename from kratos/future/utilities/xml_utilities/xml_utils.h rename to kratos/utilities/xml_utilities/xml_utils.h index eb34fbee0c9a..9daa7baed5ed 100644 --- a/kratos/future/utilities/xml_utilities/xml_utils.h +++ b/kratos/utilities/xml_utilities/xml_utils.h @@ -20,7 +20,7 @@ #include "includes/define.h" #include "xml_element.h" -namespace Kratos::Future { +namespace Kratos { ///@name Kratos Classes ///@{ @@ -67,4 +67,4 @@ class KRATOS_API(KRATOS_CORE) XmlUtilities ///@} -} // namespace Kratos::Future \ No newline at end of file +} // namespace Kratos \ No newline at end of file From 17dd545001e8469a4d7cf905707929fd918ac839 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 20 Feb 2026 07:51:33 +0100 Subject: [PATCH 104/116] update test_xml_utils --- .../utilities/test_xml_utilities.cpp | 298 ++++++------------ 1 file changed, 97 insertions(+), 201 deletions(-) diff --git a/kratos/tests/cpp_tests/utilities/test_xml_utilities.cpp b/kratos/tests/cpp_tests/utilities/test_xml_utilities.cpp index 3f5c11563794..537fe6230e7c 100644 --- a/kratos/tests/cpp_tests/utilities/test_xml_utilities.cpp +++ b/kratos/tests/cpp_tests/utilities/test_xml_utilities.cpp @@ -12,44 +12,38 @@ // System includes #include -#include -#include // External includes // Project includes #include "testing/testing.h" -#include "utilities/xml_utilities/xml_expression_element.h" -#include "utilities/xml_utilities/xml_ostream_writer.h" -#include "utilities/xml_utilities/xml_ostream_ascii_writer.h" -#include "utilities/xml_utilities/xml_ostream_base64_binary_writer.h" -#include "expression/literal_flat_expression.h" +#include "utilities/xml_utilities/xml_elements_array.h" +#include "utilities/xml_utilities/xml_ascii_nd_data_element.h" +#include "utilities/xml_utilities/xml_base64_binary_nd_data_element.h" namespace Kratos::Testing { -KRATOS_TEST_CASE_IN_SUITE(XmlElementGetTagName, KratosCoreFastSuite) +KRATOS_TEST_CASE_IN_SUITE(XmlElementsArrayGetTagName, KratosCoreFastSuite) { - XmlExpressionElement element("TestElement"); + XmlElementsArray element("TestElement"); KRATOS_EXPECT_EQ(element.GetTagName(), "TestElement"); } -KRATOS_TEST_CASE_IN_SUITE(XmlElementAddAndGetAttributes, KratosCoreFastSuite) +KRATOS_TEST_CASE_IN_SUITE(XmlElementsArrayAddAndGetAttributes, KratosCoreFastSuite) { - XmlExpressionElement element("TestElement"); + XmlElementsArray element("TestElement"); element.AddAttribute("Attribute1", "Value1"); element.AddAttribute("Attribute2", "Value2"); auto attributes = element.GetAttributes(); - KRATOS_EXPECT_EQ(attributes[0].first, "Attribute1"); - KRATOS_EXPECT_EQ(attributes[0].second, "Value1"); - KRATOS_EXPECT_EQ(attributes[1].first, "Attribute2"); - KRATOS_EXPECT_EQ(attributes[1].second, "Value2"); + KRATOS_EXPECT_EQ(attributes["Attribute1"], "Value1"); + KRATOS_EXPECT_EQ(attributes["Attribute2"], "Value2"); } -KRATOS_TEST_CASE_IN_SUITE(XmlElementClearAttributes, KratosCoreFastSuite) +KRATOS_TEST_CASE_IN_SUITE(XmlElementsArrayClearAttributes, KratosCoreFastSuite) { - XmlExpressionElement element("TestElement"); + XmlElementsArray element("TestElement"); element.AddAttribute("Attribute1", "Value1"); element.ClearAttributes(); @@ -57,33 +51,34 @@ KRATOS_TEST_CASE_IN_SUITE(XmlElementClearAttributes, KratosCoreFastSuite) KRATOS_EXPECT_EQ(attributes.size(), 0); } -KRATOS_TEST_CASE_IN_SUITE(XmlElementAddElement, KratosCoreFastSuite) +KRATOS_TEST_CASE_IN_SUITE(XmlElementsArrayAddElement, KratosCoreFastSuite) { - XmlExpressionElement element("TestElement"); - auto childElement = Kratos::make_shared("ChildElement"); + XmlElementsArray element("TestElement"); + auto childElement = Kratos::make_shared("ChildElement"); element.AddElement(childElement); auto children = element.GetElements(); KRATOS_EXPECT_EQ(children[0]->GetTagName(), "ChildElement"); } -KRATOS_TEST_CASE_IN_SUITE(XmlElementGetElements, KratosCoreFastSuite) +KRATOS_TEST_CASE_IN_SUITE(XmlElementsArrayGetElements, KratosCoreFastSuite) { - XmlExpressionElement element("TestElement"); - auto childElement1 = Kratos::make_shared("ChildElement"); - auto childElement2 = Kratos::make_shared("ChildElement2"); + XmlElementsArray element("TestElement"); + auto childElement1 = Kratos::make_shared("ChildElement"); + auto childElement2 = Kratos::make_shared("ChildElement2"); element.AddElement(childElement1); element.AddElement(childElement2); - auto children = element.GetElements("ChildElement"); - KRATOS_EXPECT_EQ(children.size(), 1); + auto children = element.GetElements(); + KRATOS_EXPECT_EQ(children.size(), 2); KRATOS_EXPECT_EQ(children[0]->GetTagName(), "ChildElement"); + KRATOS_EXPECT_EQ(children[1]->GetTagName(), "ChildElement2"); } -KRATOS_TEST_CASE_IN_SUITE(XmlElementClearElements, KratosCoreFastSuite) +KRATOS_TEST_CASE_IN_SUITE(XmlElementsArrayClearElements, KratosCoreFastSuite) { - XmlExpressionElement element("TestElement"); - auto childElement = Kratos::make_shared("ChildElement"); + XmlElementsArray element("TestElement"); + auto childElement = Kratos::make_shared("ChildElement"); element.AddElement(childElement); element.ClearElements(); @@ -91,16 +86,15 @@ KRATOS_TEST_CASE_IN_SUITE(XmlElementClearElements, KratosCoreFastSuite) KRATOS_EXPECT_EQ(children.size(), 0); } -KRATOS_TEST_CASE_IN_SUITE(XmlOStreamWriterWrite, KratosCoreFastSuite) +KRATOS_TEST_CASE_IN_SUITE(XmlElementsArrayWrite, KratosCoreFastSuite) { - XmlExpressionElement element("TestElement"); + XmlElementsArray element("TestElement"); element.AddAttribute("Attribute1", "Value1"); - auto childElement = Kratos::make_shared("ChildElement"); + auto childElement = Kratos::make_shared("ChildElement"); element.AddElement(childElement); std::stringstream ss; - XmlOStreamAsciiWriter writer(ss, 4); - writer.WriteElement(element, 1); + element.Write(ss, 1); KRATOS_EXPECT_EQ(ss.str(), " \n" @@ -108,227 +102,129 @@ KRATOS_TEST_CASE_IN_SUITE(XmlOStreamWriterWrite, KratosCoreFastSuite) " \n"); } -KRATOS_TEST_CASE_IN_SUITE(XmlOStreamWriterWriteDataElementAsciiChar, KratosCoreFastSuite) +KRATOS_TEST_CASE_IN_SUITE(XmlAsciiNDDataElementChar, KratosCoreFastSuite) { - auto char_expression_1 = LiteralFlatExpression::Create(2, {3}); - std::size_t local_index = 0; - for (auto it = char_expression_1->begin(); it != char_expression_1->end(); ++it) { - *it = local_index++; - } - - auto char_expression_2 = LiteralFlatExpression::Create(3, {3}); - local_index = 0; - for (auto it = char_expression_2->begin(); it != char_expression_2->end(); ++it) { - *it = local_index++; - } - - std::vector expressions = {char_expression_1, char_expression_2}; - XmlExpressionElement element("data_1", expressions); + DenseVector shape(2, 0); + shape[0] = 5; shape[1] = 3; + auto char_nd_data_1 = Kratos::make_shared>(shape); + auto char_nd_data_1_view = char_nd_data_1->ViewData(); + std::iota(char_nd_data_1_view.begin(), char_nd_data_1_view.begin() + 6, 0U); + std::iota(char_nd_data_1_view.begin() + 6, char_nd_data_1_view.end(), 0U); + + XmlAsciiNDDataElement element("data_1", char_nd_data_1, 9); element.AddAttribute("attribute1", "value1"); std::stringstream ss; - XmlOStreamAsciiWriter writer(ss, 4); - writer.WriteElement(element, 1); + element.Write(ss, 1); KRATOS_EXPECT_EQ(ss.str(), - " \n" + " \n" " 0 1 2 3 4 5 0 1 2 3 4 5 6 7 8\n" " \n"); } -KRATOS_TEST_CASE_IN_SUITE(XmlOStreamWriterWriteDataElementAsciiInt, KratosCoreFastSuite) +KRATOS_TEST_CASE_IN_SUITE(XmlAsciiNDDataElementInt, KratosCoreFastSuite) { - auto char_expression_1 = LiteralFlatExpression::Create(2, {3}); - std::size_t local_index = 0; - for (auto it = char_expression_1->begin(); it != char_expression_1->end(); ++it) { - *it = local_index++; - } - - auto char_expression_2 = LiteralFlatExpression::Create(3, {3}); - local_index = 0; - for (auto it = char_expression_2->begin(); it != char_expression_2->end(); ++it) { - *it = local_index++; - } - - std::vector expressions = {char_expression_1, char_expression_2}; - XmlExpressionElement element("data_1", expressions); + DenseVector shape(2, 0); + shape[0] = 5; shape[1] = 3; + auto char_nd_data_1 = Kratos::make_shared>(shape); + auto char_nd_data_1_view = char_nd_data_1->ViewData(); + std::iota(char_nd_data_1_view.begin(), char_nd_data_1_view.begin() + 6, 0U); + std::iota(char_nd_data_1_view.begin() + 6, char_nd_data_1_view.end(), 0U); + + XmlAsciiNDDataElement element("data_1", char_nd_data_1, 9); element.AddAttribute("attribute1", "value1"); std::stringstream ss; - XmlOStreamAsciiWriter writer(ss, 4); - writer.WriteElement(element, 1); + element.Write(ss, 1); KRATOS_EXPECT_EQ(ss.str(), - " \n" + " \n" " 0 1 2 3 4 5 0 1 2 3 4 5 6 7 8\n" " \n"); } -KRATOS_TEST_CASE_IN_SUITE(XmlOStreamWriterWriteDataElementAsciiDouble, KratosCoreFastSuite) -{ - auto char_expression_1 = LiteralFlatExpression::Create(2, {3}); - std::size_t local_index = 0; - for (auto it = char_expression_1->begin(); it != char_expression_1->end(); ++it) { - *it = local_index++; - } - - auto char_expression_2 = LiteralFlatExpression::Create(3, {3}); - local_index = 0; - for (auto it = char_expression_2->begin(); it != char_expression_2->end(); ++it) { - *it = local_index++; - } - - std::vector expressions = {char_expression_1, char_expression_2}; - XmlExpressionElement element("data_1", expressions); - element.AddAttribute("attribute1", "value1"); - - std::stringstream ss; - XmlOStreamAsciiWriter writer(ss, 1); - writer.WriteElement(element, 1); - - KRATOS_EXPECT_EQ(ss.str(), - " \n" - " 0.0e+00 1.0e+00 2.0e+00 3.0e+00 4.0e+00 5.0e+00 0.0e+00 1.0e+00 2.0e+00 3.0e+00 4.0e+00 5.0e+00 6.0e+00 7.0e+00 8.0e+00\n" - " \n"); -} - -KRATOS_TEST_CASE_IN_SUITE(XmlOStreamWriterWriteDataElementAsciiMixed, KratosCoreFastSuite) +KRATOS_TEST_CASE_IN_SUITE(XmlAsciiNDDataElementDouble, KratosCoreFastSuite) { - auto char_expression_1 = LiteralFlatExpression::Create(2, {3}); - std::size_t local_index = 0; - for (auto it = char_expression_1->begin(); it != char_expression_1->end(); ++it) { - *it = local_index++; - } - - auto char_expression_2 = LiteralFlatExpression::Create(3, {3}); - local_index = 0; - for (auto it = char_expression_2->begin(); it != char_expression_2->end(); ++it) { - *it = local_index++; - } - - std::vector expressions = {char_expression_1, char_expression_2}; - XmlExpressionElement element("data_1", expressions); + DenseVector shape(2, 0); + shape[0] = 5; shape[1] = 3; + auto char_nd_data_1 = Kratos::make_shared>(shape); + auto char_nd_data_1_view = char_nd_data_1->ViewData(); + std::iota(char_nd_data_1_view.begin(), char_nd_data_1_view.begin() + 6, 0.0); + std::iota(char_nd_data_1_view.begin() + 6, char_nd_data_1_view.end(), 0.0); + + XmlAsciiNDDataElement element("data_1", char_nd_data_1, 1); element.AddAttribute("attribute1", "value1"); std::stringstream ss; - XmlOStreamAsciiWriter writer(ss, 1); - writer.WriteElement(element, 1); + element.Write(ss, 1); KRATOS_EXPECT_EQ(ss.str(), - " \n" + " \n" " 0.0e+00 1.0e+00 2.0e+00 3.0e+00 4.0e+00 5.0e+00 0.0e+00 1.0e+00 2.0e+00 3.0e+00 4.0e+00 5.0e+00 6.0e+00 7.0e+00 8.0e+00\n" " \n"); } -KRATOS_TEST_CASE_IN_SUITE(XmlOStreamWriterWriteDataElementBinaryChar, KratosCoreFastSuite) +KRATOS_TEST_CASE_IN_SUITE(XmlBase64BinaryNDDataElementChar, KratosCoreFastSuite) { - auto char_expression_1 = LiteralFlatExpression::Create(2, {3}); - std::size_t local_index = 0; - for (auto it = char_expression_1->begin(); it != char_expression_1->end(); ++it) { - *it = local_index++; - } - - auto char_expression_2 = LiteralFlatExpression::Create(3, {3}); - local_index = 0; - for (auto it = char_expression_2->begin(); it != char_expression_2->end(); ++it) { - *it = local_index++; - } - - std::vector expressions = {char_expression_1, char_expression_2}; - XmlExpressionElement element("data_1", expressions); + DenseVector shape(2, 0); + shape[0] = 5; shape[1] = 3; + auto char_nd_data_1 = Kratos::make_shared>(shape); + auto char_nd_data_1_view = char_nd_data_1->ViewData(); + std::iota(char_nd_data_1_view.begin(), char_nd_data_1_view.begin() + 6, 0U); + std::iota(char_nd_data_1_view.begin() + 6, char_nd_data_1_view.end(), 0U); + + XmlBase64BinaryNDDataElement element("data_1", char_nd_data_1); element.AddAttribute("attribute1", "value1"); std::stringstream ss; - XmlOStreamBase64BinaryWriter writer(ss); - writer.WriteElement(element, 1); + element.Write(ss, 1); KRATOS_EXPECT_EQ(ss.str(), - " \n" - " DwAAAAABAgMEBQABAgMEBQYHCA==\n" - " \n"); -} - -KRATOS_TEST_CASE_IN_SUITE(XmlOStreamWriterWriteDataElementBinaryInt, KratosCoreFastSuite) -{ - auto char_expression_1 = LiteralFlatExpression::Create(2, {3}); - std::size_t local_index = 0; - for (auto it = char_expression_1->begin(); it != char_expression_1->end(); ++it) { - *it = local_index++; - } - - auto char_expression_2 = LiteralFlatExpression::Create(3, {3}); - local_index = 0; - for (auto it = char_expression_2->begin(); it != char_expression_2->end(); ++it) { - *it = local_index++; - } - - std::vector expressions = {char_expression_1, char_expression_2}; - XmlExpressionElement element("data_1", expressions); - element.AddAttribute("attribute1", "value1"); - - std::stringstream ss; - XmlOStreamBase64BinaryWriter writer(ss); - writer.WriteElement(element, 1); - - KRATOS_EXPECT_EQ(ss.str(), - " \n" - " PAAAAAAAAAABAAAAAgAAAAMAAAAEAAAABQAAAAAAAAABAAAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAA==\n" + " \n" + " DwAAAAAAAAAAAQIDBAUAAQIDBAUGBwg=\n" " \n"); } -KRATOS_TEST_CASE_IN_SUITE(XmlOStreamWriterWriteDataElementBinaryDouble, KratosCoreFastSuite) +KRATOS_TEST_CASE_IN_SUITE(XmlBase64BinaryNDDataElementInt, KratosCoreFastSuite) { - auto char_expression_1 = LiteralFlatExpression::Create(2, {3}); - std::size_t local_index = 0; - for (auto it = char_expression_1->begin(); it != char_expression_1->end(); ++it) { - *it = local_index++; - } - - auto char_expression_2 = LiteralFlatExpression::Create(3, {3}); - local_index = 0; - for (auto it = char_expression_2->begin(); it != char_expression_2->end(); ++it) { - *it = local_index++; - } - - std::vector expressions = {char_expression_1, char_expression_2}; - XmlExpressionElement element("data_1", expressions); + DenseVector shape(2, 0); + shape[0] = 5; shape[1] = 3; + auto char_nd_data_1 = Kratos::make_shared>(shape); + auto char_nd_data_1_view = char_nd_data_1->ViewData(); + std::iota(char_nd_data_1_view.begin(), char_nd_data_1_view.begin() + 6, 0U); + std::iota(char_nd_data_1_view.begin() + 6, char_nd_data_1_view.end(), 0U); + + XmlBase64BinaryNDDataElement element("data_1", char_nd_data_1); element.AddAttribute("attribute1", "value1"); std::stringstream ss; - XmlOStreamBase64BinaryWriter writer(ss); - writer.WriteElement(element, 1); + element.Write(ss, 1); KRATOS_EXPECT_EQ(ss.str(), - " \n" - " eAAAAAAAAAAAAAAAAAAAAAAA8D8AAAAAAAAAQAAAAAAAAAhAAAAAAAAAEEAAAAAAAAAUQAAAAAAAAAAAAAAAAAAA8D8AAAAAAAAAQAAAAAAAAAhAAAAAAAAAEEAAAAAAAAAUQAAAAAAAABhAAAAAAAAAHEAAAAAAAAAgQA==\n" + " \n" + " PAAAAAAAAAAAAAAAAQAAAAIAAAADAAAABAAAAAUAAAAAAAAAAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAA=\n" " \n"); } -KRATOS_TEST_CASE_IN_SUITE(XmlOStreamWriterWriteDataElementBinaryMixed, KratosCoreFastSuite) +KRATOS_TEST_CASE_IN_SUITE(XmlBase64BinaryNDDataElementDouble, KratosCoreFastSuite) { - auto char_expression_1 = LiteralFlatExpression::Create(2, {3}); - std::size_t local_index = 0; - for (auto it = char_expression_1->begin(); it != char_expression_1->end(); ++it) { - *it = local_index++; - } - - auto char_expression_2 = LiteralFlatExpression::Create(3, {3}); - local_index = 0; - for (auto it = char_expression_2->begin(); it != char_expression_2->end(); ++it) { - *it = local_index++; - } - - std::vector expressions = {char_expression_1, char_expression_2}; - XmlExpressionElement element("data_1", expressions); + DenseVector shape(2, 0); + shape[0] = 5; shape[1] = 3; + auto char_nd_data_1 = Kratos::make_shared>(shape); + auto char_nd_data_1_view = char_nd_data_1->ViewData(); + std::iota(char_nd_data_1_view.begin(), char_nd_data_1_view.begin() + 6, 0U); + std::iota(char_nd_data_1_view.begin() + 6, char_nd_data_1_view.end(), 0U); + + XmlBase64BinaryNDDataElement element("data_1", char_nd_data_1); element.AddAttribute("attribute1", "value1"); std::stringstream ss; - XmlOStreamBase64BinaryWriter writer(ss); - writer.WriteElement(element, 1); + element.Write(ss, 1); KRATOS_EXPECT_EQ(ss.str(), - " \n" - " eAAAAAAAAAAAAAAAAAAAAAAA8D8AAAAAAAAAQAAAAAAAAAhAAAAAAAAAEEAAAAAAAAAUQAAAAAAAAAAAAAAAAAAA8D8AAAAAAAAAQAAAAAAAAAhAAAAAAAAAEEAAAAAAAAAUQAAAAAAAABhAAAAAAAAAHEAAAAAAAAAgQA==\n" + " \n" + " eAAAAAAAAAAAAAAAAAAAAAAAAAAAAPA/AAAAAAAAAEAAAAAAAAAIQAAAAAAAABBAAAAAAAAAFEAAAAAAAAAAAAAAAAAAAPA/AAAAAAAAAEAAAAAAAAAIQAAAAAAAABBAAAAAAAAAFEAAAAAAAAAYQAAAAAAAABxAAAAAAAAAIEA=\n" " \n"); } From 6cee9af2467c21ede0b8842638ad4a81cd81c990 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 20 Feb 2026 08:17:36 +0100 Subject: [PATCH 105/116] fix order issue with the Configuration exposure --- kratos/input_output/vtu_output.cpp | 4 ++-- kratos/input_output/vtu_output.h | 4 ++-- kratos/python/add_io_to_python.cpp | 4 ++-- .../builder_and_solvers/p_multigrid/status_stream.cpp | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/kratos/input_output/vtu_output.cpp b/kratos/input_output/vtu_output.cpp index 52b9f1492b75..d2fa78bd6438 100644 --- a/kratos/input_output/vtu_output.cpp +++ b/kratos/input_output/vtu_output.cpp @@ -832,7 +832,7 @@ std::pair::i VtuOutput::VtuOutput( ModelPart& rModelPart, - const Globals::Configuration Configuration, + const bool IsInitialConfiguration, const WriterFormat OutputFormat, const IndexType Precision, const bool OutputSubModelParts, @@ -840,7 +840,7 @@ VtuOutput::VtuOutput( const IndexType EchoLevel) : mIsPVDFileHeaderWritten(false), mrModelPart(rModelPart), - mConfiguration(Configuration), + mConfiguration(IsInitialConfiguration ? Globals::Configuration::Initial : Globals::Configuration::Current), mEchoLevel(EchoLevel), mOutputFormat(OutputFormat), mPrecision(Precision) diff --git a/kratos/input_output/vtu_output.h b/kratos/input_output/vtu_output.h index 45b6e59a4373..b711bc4395a7 100644 --- a/kratos/input_output/vtu_output.h +++ b/kratos/input_output/vtu_output.h @@ -135,7 +135,7 @@ class KRATOS_API(KRATOS_CORE) VtuOutput : public IO * @brief Construct a new Vtu Output * * @param rModelPart Model part to be used in the vtu output. - * @param Configuration Which nodal positions to be written out. + * @param IsInitialConfiguration Which nodal positions to be written out. * @param OutputFormat The format of the output. * @param Precision Precision of the double values to be used when writing the doubles as ASCII. * @param OutputSubModelParts To consider all the submodel parts recursively for output. @@ -144,7 +144,7 @@ class KRATOS_API(KRATOS_CORE) VtuOutput : public IO */ VtuOutput( ModelPart& rModelPart, - const Globals::Configuration Configuration, + const bool IsInitialConfiguration = true, const WriterFormat OutputFormat = WriterFormat::COMPRESSED_RAW, const IndexType Precision = 9, const bool OutputSubModelParts = false, diff --git a/kratos/python/add_io_to_python.cpp b/kratos/python/add_io_to_python.cpp index 5eb4623153d3..59afd43cf832 100644 --- a/kratos/python/add_io_to_python.cpp +++ b/kratos/python/add_io_to_python.cpp @@ -215,9 +215,9 @@ void AddIOToPython(pybind11::module& m) ; vtu_output - .def(py::init(), + .def(py::init(), py::arg("model_part"), - py::arg("configuration") = Globals::Configuration::Initial, + py::arg("is_initial_configuration") = true, py::arg("output_format") = VtuOutput::WriterFormat::COMPRESSED_RAW, py::arg("precision") = 9, py::arg("output_sub_model_parts") = false, diff --git a/kratos/solving_strategies/builder_and_solvers/p_multigrid/status_stream.cpp b/kratos/solving_strategies/builder_and_solvers/p_multigrid/status_stream.cpp index 6a2955c6d067..8bf7654295b2 100644 --- a/kratos/solving_strategies/builder_and_solvers/p_multigrid/status_stream.cpp +++ b/kratos/solving_strategies/builder_and_solvers/p_multigrid/status_stream.cpp @@ -42,7 +42,7 @@ using SingleBnS = PMultigridBuilderAndSolver, std::unique_ptr MakeVtuOutput(ModelPart& rModelPart, const PointerVectorSet>& rDofSet) { - auto p_output = std::make_unique(rModelPart, Globals::Configuration::Initial); + auto p_output = std::make_unique(rModelPart); KRATOS_TRY From 18fbd870ee248e6f762ea3b5b9d05f1a4e1ec3df Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 20 Feb 2026 08:17:53 +0100 Subject: [PATCH 106/116] update vtu_output tests --- kratos/future/tests/test_KratosFutureCore.py | 4 - kratos/future/tests/test_vtu_output.py | 585 ------------------- kratos/tests/test_vtu_output.py | 575 ++++++++++++++++-- 3 files changed, 535 insertions(+), 629 deletions(-) delete mode 100644 kratos/future/tests/test_vtu_output.py mode change 100644 => 100755 kratos/tests/test_vtu_output.py diff --git a/kratos/future/tests/test_KratosFutureCore.py b/kratos/future/tests/test_KratosFutureCore.py index 55fc6c6d82cd..f5766f865d86 100644 --- a/kratos/future/tests/test_KratosFutureCore.py +++ b/kratos/future/tests/test_KratosFutureCore.py @@ -5,7 +5,6 @@ import KratosMultiphysics.KratosUnittest as KratosUnittest # Import the tests or test_classes to create the suites -import test_vtu_output import test_linear_system import test_sparse_matrix_linear_operator @@ -28,9 +27,6 @@ def AssembleTestSuites(): smallSuite = suites['small'] smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_linear_system.TestLinearSystem])) smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_sparse_matrix_linear_operator.TestSparseMatrixLinearOperator])) - smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_vtu_output.TestVtuOutput2D])) - smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_vtu_output.TestVtuOutput3D])) - smallSuite.addTests(KratosUnittest.TestLoader().loadTestsFromTestCases([test_vtu_output.TestVtuOutput])) # Create a test suite with the selected tests plus all small tests nightSuite = suites['nightly'] diff --git a/kratos/future/tests/test_vtu_output.py b/kratos/future/tests/test_vtu_output.py deleted file mode 100644 index 85e3dad5f43e..000000000000 --- a/kratos/future/tests/test_vtu_output.py +++ /dev/null @@ -1,585 +0,0 @@ -import math, typing -from pathlib import Path -import xml.etree.ElementTree as ET - -import KratosMultiphysics as Kratos -import KratosMultiphysics.KratosUnittest as kratos_unittest -import KratosMultiphysics.kratos_utilities as kratos_utils -from KratosMultiphysics.compare_two_files_check_process import CompareTwoFilesCheckProcess - -# import from the tests -with kratos_unittest.WorkFolderScope("../../tests", __file__, True): - from test_vtk_output_process import SetupModelPart2D, SetupModelPart3D - -class TestVtuOutputBase: - @classmethod - def SetSolution(cls): - node: Kratos.Node - for node in cls.model_part.Nodes: - node.SetSolutionStepValue(Kratos.DISPLACEMENT, 0,[node.X * 2, node.Y * 3, node.Z * 4]) - node.SetSolutionStepValue(Kratos.VELOCITY, 0,[node.X * 5, node.Y * 6, node.Z * 7]) - node.SetSolutionStepValue(Kratos.PRESSURE, 0, node.Id * 8.0) - - elem: Kratos.Element - for i_elem, elem in enumerate(cls.model_part.Elements): - elem.SetValue(Kratos.DETERMINANT, [i_elem*0.189, i_elem * 1.236, i_elem * 2.365]) - - cond: Kratos.Condition - for i_cond, cond in enumerate(cls.model_part.Conditions): - cond.SetValue(Kratos.DENSITY, i_cond * 4.362) - cond.SetValue(Kratos.YOUNG_MODULUS, i_cond * 5.326) - cond.SetValue(Kratos.DETERMINANTS_OF_JACOBIAN_PARENT, Kratos.Vector()) - - @classmethod - def setUpClass(cls, output_prefix: str, setup_method, output_sub_model_parts: bool) -> None: - cls.model = Kratos.Model() - cls.model_part = cls.model.CreateModelPart("test") - cls.model_part.ProcessInfo[Kratos.STEP] = 0 - cls.model_part.ProcessInfo[Kratos.TIME] = 1.0 - cls.output_prefix = output_prefix - cls.output_sub_model_parts = output_sub_model_parts - setup_method(cls.model_part) - cls.SetSolution() - - def WriteVtu(self, output_format: Kratos.Future.VtuOutput.WriterFormat, error_check = False): - vtu_output = Kratos.Future.VtuOutput(self.model_part, Kratos.Configuration.Initial, output_format, 9, echo_level=0, output_sub_model_parts=self.output_sub_model_parts, write_ids=True) - vtu_output.AddVariable(Kratos.PRESSURE, Kratos.Globals.DataLocation.NodeHistorical) - vtu_output.AddVariable(Kratos.VELOCITY, Kratos.Globals.DataLocation.NodeHistorical) - vtu_output.AddVariable(Kratos.DISPLACEMENT, Kratos.Globals.DataLocation.NodeHistorical) - vtu_output.AddVariable(Kratos.DETERMINANT, Kratos.Globals.DataLocation.Element) - vtu_output.AddVariable(Kratos.DENSITY, Kratos.Globals.DataLocation.Condition) - vtu_output.AddVariable(Kratos.YOUNG_MODULUS, Kratos.Globals.DataLocation.Condition) - if error_check: - # adds a vector with zero size to check for the error. Because, in vtu lib, - # if the behavior is undefined if the "NumberOfComponents = 0". - vtu_output.AddVariable(Kratos.DETERMINANTS_OF_JACOBIAN_PARENT, Kratos.Globals.DataLocation.Condition) - - ta_1 = Kratos.TensorAdaptors.HistoricalVariableTensorAdaptor(self.model_part.Nodes, Kratos.PRESSURE) - ta_1.CollectData() - ta_2 = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Elements, Kratos.DETERMINANT) - ta_2.CollectData() - - ta_1.data *= 3 - ta_2.data *= 3 - - vtu_output.AddTensorAdaptor("hist_ta", ta_1) - vtu_output.AddTensorAdaptor("elem_ta", ta_2) - - with kratos_unittest.WorkFolderScope("vtk_output_process_ref_files", __file__, True): - output_file_prefix = output_format.name.lower() + self.output_prefix + "/Main" - vtu_output.PrintOutput("temp/" + output_file_prefix) - self.Check("temp/" + output_file_prefix, output_file_prefix) - - def test_WriteMeshAscii(self): - self.WriteVtu(Kratos.Future.VtuOutput.ASCII) - - def test_WriteMeshBinary(self): - self.WriteVtu(Kratos.Future.VtuOutput.BINARY) - - def test_WriteMeshRaw(self): - self.WriteVtu(Kratos.Future.VtuOutput.RAW) - - def test_WriteMeshCompressedRaw(self): - self.WriteVtu(Kratos.Future.VtuOutput.COMPRESSED_RAW) - - def test_WriteMeshAsciiWithError(self): - self.addCleanup(kratos_utils.DeleteDirectoryIfExisting, "vtk_output_process_ref_files/temp") - with self.assertRaises(RuntimeError): - self.WriteVtu(Kratos.Future.VtuOutput.ASCII, True) - - def test_WriteMeshBinaryWithError(self): - self.addCleanup(kratos_utils.DeleteDirectoryIfExisting, "vtk_output_process_ref_files/temp") - with self.assertRaises(RuntimeError): - self.WriteVtu(Kratos.Future.VtuOutput.BINARY, True) - - def test_WriteMeshRawWithError(self): - self.addCleanup(kratos_utils.DeleteDirectoryIfExisting, "vtk_output_process_ref_files/temp") - with self.assertRaises(RuntimeError): - self.WriteVtu(Kratos.Future.VtuOutput.RAW, True) - - def test_WriteMeshCompressedRawWithError(self): - self.addCleanup(kratos_utils.DeleteDirectoryIfExisting, "vtk_output_process_ref_files/temp") - with self.assertRaises(RuntimeError): - self.WriteVtu(Kratos.Future.VtuOutput.COMPRESSED_RAW, True) - - def Check(self, output_prefix, reference_prefix): - def check_file(output_file_name: str, reference_file_name: str): - ## Settings string in json format - params = Kratos.Parameters("""{ - "reference_file_name" : "", - "output_file_name" : "", - "comparison_type" : "deterministic" - }""") - params["reference_file_name"].SetString(reference_file_name) - params["output_file_name"].SetString(output_file_name) - CompareTwoFilesCheckProcess(params).Execute() - - for file_path in Path(reference_prefix).iterdir(): - self.assertTrue((Path(output_prefix) / file_path.name).is_file(), msg=f"\"{(Path(output_prefix) / file_path.name)}\" is not a file.") - check_file(f"{output_prefix}/{file_path.name}", str(file_path)) - check_file(f"{output_prefix}.pvd", f"{reference_prefix}.pvd") - - kratos_utils.DeleteDirectoryIfExistingAndEmpty("temp") - -class TestVtuOutput2D(TestVtuOutputBase, kratos_unittest.TestCase): - @classmethod - def setUpClass(cls) -> None: - super().setUpClass("2D", SetupModelPart2D, output_sub_model_parts = True) - -class TestVtuOutput3D(TestVtuOutputBase, kratos_unittest.TestCase): - @classmethod - def setUpClass(cls) -> None: - # the method SetupModelPart3D does not create sub model parts - # with nodes which do not include nodes from its conditions or elements. It uses - # some random nodes. Hence sub_model_part output is disabled. - super().setUpClass("3D", SetupModelPart3D, output_sub_model_parts = False) - -class TestVtuOutput(kratos_unittest.TestCase): - @classmethod - def setUpClass(cls): - cls.data_location = Kratos.Globals.DataLocation - - cls.model = Kratos.Model() - cls.model_part = cls.model.CreateModelPart("test") - cls.model_part.AddNodalSolutionStepVariable(Kratos.STEP) - cls.model_part.AddNodalSolutionStepVariable(Kratos.PRESSURE) - cls.model_part.AddNodalSolutionStepVariable(Kratos.DISPLACEMENT) - cls.model_part.AddNodalSolutionStepVariable(Kratos.DETERMINANTS_OF_JACOBIAN_PARENT) - cls.model_part.AddNodalSolutionStepVariable(Kratos.CONSTITUTIVE_MATRIX) - - cls.model_part.ProcessInfo[Kratos.TIME] = 1 - - # creating a circular pie with origin (0, 0) - radius = 1.0 - number_of_elements_or_conditions = 50 - angle = 2 * math.pi / number_of_elements_or_conditions - - cls.model_part.CreateNewNode(1, 0, 0, 0) # origin node - for i in range(number_of_elements_or_conditions): - theta = i * angle - cls.model_part.CreateNewNode(i + 2, radius * math.cos(theta), radius * math.sin(theta), 0.0) - - prop = cls.model_part.CreateNewProperties(1) - for i in range(number_of_elements_or_conditions): - cls.model_part.CreateNewElement("Element2D3N", i + 1, [1, i + 2, (i + 1) % (number_of_elements_or_conditions) + 2], prop) - cls.model_part.CreateNewCondition("LineCondition2D2N", i + 1, [i + 2, (i + 1) % (number_of_elements_or_conditions) + 2], prop) - - # create the sub model part structure - for j in range(4): - l_1 = j // 9 - l_2 = (j // 3) % 3 - l_3 = j % 3 - model_part = cls.model_part.CreateSubModelPart(f"mp_{l_1}.mp_{l_2}.mp_{l_3}") - # fill the sub range - for i in range(number_of_elements_or_conditions): - if (j % 2 == 0): - if (i % ((l_1 + 1) * (l_2 + 1) * (l_3 + 1)) == 0): - model_part.AddCondition(cls.model_part.GetCondition(i + 1)) - else: - if (i % ((l_1 + 1) * (l_2 + 1) * (l_3 + 1)) == 1): - model_part.AddElement(cls.model_part.GetElement(i + 1)) - - # now recursively fill the nodes - def fill_nodes(model_part: Kratos.ModelPart): - list_of_node_ids: 'list[int]' = [] - for condition in model_part.Conditions: - for node in condition.GetGeometry(): - list_of_node_ids.append(node.Id) - for element in model_part.Elements: - for node in element.GetGeometry(): - list_of_node_ids.append(node.Id) - - model_part.AddNodes(list_of_node_ids) - - for sub_model_part in model_part.SubModelParts: - fill_nodes(sub_model_part) - - fill_nodes(cls.model_part) - - def add_variables(container, setter): - for entity in container: - setter(entity, Kratos.STEP, entity.Id * 2) - setter(entity, Kratos.PRESSURE, entity.Id) - setter(entity, Kratos.DISPLACEMENT, Kratos.Array3([entity.Id, entity.Id + 1, entity.Id + 2])) - setter(entity, Kratos.DETERMINANTS_OF_JACOBIAN_PARENT, Kratos.Vector([entity.Id, entity.Id + 1, entity.Id + 2, entity.Id + 3, entity.Id + 4])) - setter(entity, Kratos.CONSTITUTIVE_MATRIX, Kratos.Matrix([[entity.Id, entity.Id + 1], [entity.Id + 2, entity.Id + 3], [entity.Id + 4, entity.Id + 5]])) - - add_variables(cls.model_part.Nodes, lambda x, y, z: x.SetSolutionStepValue(y, z)) - add_variables(cls.model_part.Nodes, lambda x, y, z: x.SetValue(y, z)) - add_variables(cls.model_part.Conditions, lambda x, y, z: x.SetValue(y, z)) - add_variables(cls.model_part.Elements, lambda x, y, z: x.SetValue(y, z)) - - def setUp(self): - self.model_part.ProcessInfo[Kratos.STEP] = 0 - - def test_GetOutputContainerList(self): - unstructured_grid_list = self.GetUnstructuredGridList(self.model_part, self.model_part.GetRootModelPart().GetCommunicator().GetDataCommunicator(), True) - - vtu_output = Kratos.Future.VtuOutput(self.model_part, output_sub_model_parts=True, output_format=Kratos.Future.VtuOutput.BINARY) - list_of_containers = vtu_output.GetOutputContainerList() - - list_of_ref_containers = [] - for mp, is_nodes_used, cells_container in unstructured_grid_list: - if is_nodes_used: - list_of_ref_containers.append(mp.Nodes) - list_of_ref_containers.append(mp.GetCommunicator().LocalMesh().Nodes) - - if cells_container is not None: - list_of_ref_containers.append(cells_container) - if isinstance(cells_container, Kratos.ConditionsArray): - list_of_ref_containers.append(mp.GetCommunicator().LocalMesh().Conditions) - elif isinstance(cells_container, Kratos.ElementsArray): - list_of_ref_containers.append(mp.GetCommunicator().LocalMesh().Elements) - - self.assertEqual(list_of_containers, list_of_ref_containers) - - def test_PointVariableAddition(self): - vtu_output = Kratos.Future.VtuOutput(self.model_part, output_sub_model_parts=True, output_format=Kratos.Future.VtuOutput.BINARY) - vtu_output.AddVariable(Kratos.PRESSURE, self.data_location.NodeHistorical) - vtu_output.AddVariable(Kratos.PRESSURE, self.data_location.Condition) - vtu_output.AddVariable(Kratos.PRESSURE, self.data_location.Element) - vtu_output.AddIntegrationPointVariable(Kratos.PRESSURE, self.data_location.Condition) - vtu_output.AddIntegrationPointVariable(Kratos.PRESSURE, self.data_location.Element) - - with self.assertRaises(RuntimeError): - vtu_output.AddVariable(Kratos.PRESSURE, self.data_location.NodeHistorical) - - with self.assertRaises(RuntimeError): - vtu_output.AddVariable(Kratos.PRESSURE, self.data_location.NodeNonHistorical) - - ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(self.model_part.Nodes, Kratos.DoubleNDData([51, 5])) - ta.Check() - with self.assertRaises(RuntimeError): - vtu_output.AddTensorAdaptor("PRESSURE", ta) - vtu_output.AddTensorAdaptor("PRESSURE_1", ta) - - with self.assertRaises(RuntimeError): - vtu_output.AddTensorAdaptor("PRESSURE_1", ta) - vtu_output.AddTensorAdaptor("PRESSURE_2", ta) - - ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(self.model_part.Conditions, Kratos.DoubleNDData([50,2,4])) - ta.Check() - with self.assertRaises(RuntimeError): - vtu_output.AddTensorAdaptor("PRESSURE", ta) - vtu_output.AddTensorAdaptor("PRESSURE_1", ta) - vtu_output.AddTensorAdaptor("PRESSURE_2", ta) - vtu_output.AddTensorAdaptor("PRESSURE_3", ta) - - ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(self.model_part.Elements, Kratos.DoubleNDData([50,2,5])) - ta.Check() - with self.assertRaises(RuntimeError): - vtu_output.AddTensorAdaptor("PRESSURE", ta) - vtu_output.AddTensorAdaptor("PRESSURE_1", ta) - vtu_output.AddTensorAdaptor("PRESSURE_2", ta) - vtu_output.AddTensorAdaptor("PRESSURE_3", ta) - - vtu_output.PrintOutput("temp/vtu_output/variable_test") - - model_part = vtu_output.GetModelPart() - unstructured_grid_list = self.GetUnstructuredGridList(model_part, model_part.GetCommunicator().GetDataCommunicator(), True) - list_of_vtu_file_names: 'list[str]' = [] - for model_part, use_nodes, container in unstructured_grid_list: - vtu_file_name = TestVtuOutput.GetUnstructuredGridName((model_part, use_nodes, container), "temp/vtu_output/variable_test", 0, model_part.GetCommunicator().GetDataCommunicator()) - list_of_vtu_file_names.append(vtu_file_name) - if model_part.FullName() == "test": - if use_nodes: - TestVtuOutput.CheckVtuFile(self, vtu_file_name, model_part.NumberOfNodes(), len(container), "binary", - { - "PRESSURE": (1, "Float64"), - "PRESSURE_1": (5, "Float64"), - "PRESSURE_2": (5, "Float64") - }, - { - "PRESSURE": (1, "Float64") - }) - elif isinstance(container, Kratos.ConditionsArray): - TestVtuOutput.CheckVtuFile(self, vtu_file_name, TestVtuOutput.GetNumberOfNodes(container), len(container), "binary", - {}, - { - "PRESSURE": (1, "Float64"), - "PRESSURE_1": (8, "Float64"), - "PRESSURE_2": (8, "Float64"), - "PRESSURE_3": (8, "Float64") - }) - elif isinstance(container, Kratos.ElementsArray): - TestVtuOutput.CheckVtuFile(self, vtu_file_name, TestVtuOutput.GetNumberOfNodes(container), len(container), "binary", - { - "PRESSURE": (1, "Float64"), - "PRESSURE_1": (5, "Float64"), - "PRESSURE_2": (1, "Float64"), - "PRESSURE_3": (5, "Float64") - }, - { - "PRESSURE": (1, "Float64"), - "PRESSURE_1": (10, "Float64"), - "PRESSURE_2": (10, "Float64"), - "PRESSURE_3": (10, "Float64") - }) - else: - if use_nodes: - TestVtuOutput.CheckVtuFile(self, vtu_file_name, model_part.NumberOfNodes(), len(container), "binary", - { - "PRESSURE": (1, "Float64") - }, - { - "PRESSURE": (1, "Float64") - }) - else: - TestVtuOutput.CheckVtuFile(self, vtu_file_name, TestVtuOutput.GetNumberOfNodes(container), len(container), "binary", - { - }, - { - "PRESSURE": (1, "Float64") - }) - # check gauss - list_of_vtu_file_names.append(TestVtuOutput.CheckGaussVtuFile(self, model_part, container, "temp/vtu_output/variable_test", 0, "binary", model_part.GetCommunicator().GetDataCommunicator(), - { - "PRESSURE": (1, "Float64") - })) - TestVtuOutput.CheckPvdFile(self, "temp/vtu_output/variable_test.pvd", list_of_vtu_file_names, [1 + 1e-9]) - - def test_CellVariableAddition(self): - vtu_output = Kratos.Future.VtuOutput(self.model_part, output_format=Kratos.Future.VtuOutput.ASCII, output_sub_model_parts=True) - vtu_output.AddVariable(Kratos.PRESSURE, self.data_location.Condition) - vtu_output.AddVariable(Kratos.PRESSURE, self.data_location.NodeHistorical) - vtu_output.AddVariable(Kratos.PRESSURE, self.data_location.Element) - vtu_output.AddIntegrationPointVariable(Kratos.PRESSURE, self.data_location.Condition) - vtu_output.AddIntegrationPointVariable(Kratos.PRESSURE, self.data_location.Element) - - vtu_output.AddVariable(Kratos.DISPLACEMENT, self.data_location.Element) - vtu_output.AddVariable(Kratos.DISPLACEMENT, self.data_location.NodeHistorical) - vtu_output.AddVariable(Kratos.DISPLACEMENT, self.data_location.Condition) - vtu_output.AddIntegrationPointVariable(Kratos.DISPLACEMENT, self.data_location.Condition) - vtu_output.AddIntegrationPointVariable(Kratos.DISPLACEMENT, self.data_location.Element) - - vtu_output.PrintOutput("temp/vtu_output/time_step_test") - vtu_output.GetModelPart().ProcessInfo[Kratos.TIME] += 1e-9 - vtu_output.GetModelPart().ProcessInfo[Kratos.STEP] += 1 - vtu_output.PrintOutput("temp/vtu_output/time_step_test") - - model_part = vtu_output.GetModelPart() - unstructured_grid_list = self.GetUnstructuredGridList(model_part, model_part.GetCommunicator().GetDataCommunicator(), True) - list_of_vtu_file_names: 'list[str]' = [] - for step in range(2): - for model_part, use_nodes, container in unstructured_grid_list: - vtu_file_name = TestVtuOutput.GetUnstructuredGridName((model_part, use_nodes, container), "temp/vtu_output/time_step_test", step, model_part.GetCommunicator().GetDataCommunicator()) - list_of_vtu_file_names.append(vtu_file_name) - if use_nodes: - TestVtuOutput.CheckVtuFile(self, vtu_file_name, model_part.NumberOfNodes(), len(container), "ascii", - { - "PRESSURE": (1, "Float64"), - "DISPLACEMENT": (3, "Float64") - }, - { - "PRESSURE": (1, "Float64"), - "DISPLACEMENT": (3, "Float64") - }) - else: - TestVtuOutput.CheckVtuFile(self, vtu_file_name, TestVtuOutput.GetNumberOfNodes(container), len(container), "ascii", - { - }, - { - "PRESSURE": (1, "Float64"), - "DISPLACEMENT": (3, "Float64") - }) - - # check gauss - list_of_vtu_file_names.append(TestVtuOutput.CheckGaussVtuFile(self, model_part, container, "temp/vtu_output/time_step_test", step, "ascii", model_part.GetCommunicator().GetDataCommunicator(), - { - "DISPLACEMENT": (3, "Float64") - })) - - TestVtuOutput.CheckPvdFile(self, "temp/vtu_output/time_step_test.pvd", list_of_vtu_file_names, [1, 1 + 1e-9]) - - @staticmethod - def GetUnstructuredGridList(model_part: Kratos.ModelPart, data_communicator: Kratos.DataCommunicator, recursively: bool) -> 'list[tuple[Kratos.ModelPart, bool, typing.Optional[typing.Union[Kratos.ConditionsArray, Kratos.ElementsArray]]]]': - unstructured_grid_list: 'list[tuple[Kratos.ModelPart, bool, typing.Optional[typing.Union[Kratos.ConditionsArray, Kratos.ElementsArray]]]]' = [] - TestVtuOutput.__GetUnstructuredGridList(unstructured_grid_list, model_part, data_communicator, recursively) - return sorted(unstructured_grid_list, key = lambda x: x[0].FullName()) - - @staticmethod - def GetUnstructuredGridName(unstructured_grid: 'tuple[Kratos.ModelPart, bool, typing.Optional[typing.Union[Kratos.ConditionsArray, Kratos.ElementsArray]]]', prefix: str, step: int, data_communicator: Kratos.DataCommunicator, entity_suffix = "s") -> str: - if data_communicator.IsDistributed(): - rank_suffix = f"_{data_communicator.Rank()}" - else: - rank_suffix = "" - - if unstructured_grid[2] is None: - entity_type = "node" - elif isinstance(unstructured_grid[2], Kratos.ConditionsArray): - entity_type = "condition" - elif isinstance(unstructured_grid[2], Kratos.ElementsArray): - entity_type = "element" - return f"{prefix}/{unstructured_grid[0].FullName()}_{entity_type}{entity_suffix}_{step}{rank_suffix}.vtu" - - @staticmethod - def GetNodes(model_part: Kratos.ModelPart, use_model_part_nodes: bool, container: 'typing.Union[Kratos.ConditionsArray, Kratos.ElementsArray]') -> 'list[Kratos.Node]': - if use_model_part_nodes: - return model_part.Nodes - else: - temp = [] - for entity in container: - for node in entity.GetGeometry(): - temp.append(node.Id) - return [model_part.GetRootModelPart().GetNode(node_id) for node_id in list(sorted(set(temp)))] - - def GetNumberOfNodes(container: 'typing.Union[Kratos.ConditionsArray, Kratos.ElementsArray]') -> int: - temp = [] - for entity in container: - for node in entity.GetGeometry(): - temp.append(node.Id) - return len(list(set(temp))) - - @staticmethod - def CheckDataArray(test_class: kratos_unittest.TestCase, xml_element: ET.Element, number_of_components: int, name: str, data_type: str, data_format: 'typing.Optional[str]' = None): - test_class.assertEqual(xml_element.get("NumberOfComponents"), str(number_of_components)) - test_class.assertEqual(xml_element.get("type"), data_type) - test_class.assertEqual(xml_element.get("Name"), name) - if data_format is not None: - test_class.assertEqual(xml_element.get("format"), data_format) - - @staticmethod - def CheckVtuFile( - test_class: kratos_unittest.TestCase, - vtu_file_name: str, - number_of_points: int, - number_of_cells: 'typing.Optional[int]', - data_format : str, - point_data_fields: 'dict[str, tuple[int, str]]', - cell_data_fields: 'dict[str, tuple[int, str]]'): - - test_class.assertTrue(Path(vtu_file_name).is_file(), f"The file {vtu_file_name} not found.") - tree = ET.parse(vtu_file_name) - root = tree.getroot() - - test_class.assertEqual(root.tag, "VTKFile") - test_class.assertEqual(root.get("type"), "UnstructuredGrid") - test_class.assertEqual(root.get("version"), "0.1") - - unstructured_grid = root.find("UnstructuredGrid") - piece = unstructured_grid.find("Piece") - - if number_of_cells is None: - local_number_of_cells = 0 - else: - local_number_of_cells = number_of_cells - - test_class.assertEqual(piece.get("NumberOfPoints"), f"{number_of_points}", f"Vtu file name = {vtu_file_name}") - test_class.assertEqual(piece.get("NumberOfCells"), f"{local_number_of_cells}", f"Vtu file name = {vtu_file_name}") - - points = piece.find("Points") - TestVtuOutput.CheckDataArray(test_class, points.find("DataArray"), 3, "Position", "Float64", data_format) - - cells = piece.find("Cells") - if not number_of_cells is None: - data_arrays = cells.findall("DataArray") - TestVtuOutput.CheckDataArray(test_class, data_arrays[0], 1, "connectivity", "Int32", data_format) - TestVtuOutput.CheckDataArray(test_class, data_arrays[1], 1, "offsets", "Int32", data_format) - TestVtuOutput.CheckDataArray(test_class, data_arrays[2], 1, "types", "UInt8", data_format) - - # now checking for point data - point_data = piece.find("PointData") - for data_field_name, (data_field_number_of_components, data_field_data_type) in point_data_fields.items(): - found = False - for point_data_array in point_data.findall("DataArray"): - if point_data_array.get("Name") == data_field_name: - TestVtuOutput.CheckDataArray(test_class, point_data_array, data_field_number_of_components, data_field_name, data_field_data_type, data_format) - found = True - break - test_class.assertTrue(found, f"Point data field \"{data_field_name}\" not found in the \"{vtu_file_name}\"") - - if not number_of_cells is None: - # now checking for cell data - cell_data = piece.find("CellData") - for data_field_name, (data_field_number_of_components, data_field_data_type) in cell_data_fields.items(): - found = False - for point_data_array in cell_data.findall("DataArray"): - if point_data_array.get("Name") == data_field_name: - TestVtuOutput.CheckDataArray(test_class, point_data_array, data_field_number_of_components, data_field_name, data_field_data_type, data_format) - found = True - break - test_class.assertTrue(found, f"Cell data field \"{data_field_name}\" not found in the \"{vtu_file_name}\"") - kratos_utils.DeleteFileIfExisting(vtu_file_name) - - @staticmethod - def CheckPvdFile(test_class: kratos_unittest.TestCase, pvd_file_name: str, vtu_file_name_list: 'list[str]', time_step_list: 'list[float]'): - test_class.assertTrue(Path(pvd_file_name).is_file(), f"The file {pvd_file_name} not found.") - tree = ET.parse(pvd_file_name) - root = tree.getroot() - - test_class.assertEqual(root.tag, "VTKFile") - test_class.assertEqual(root.get("type"), "Collection") - test_class.assertEqual(root.get("version"), "1.0") - - collection = root.find("Collection") - datasets = collection.findall("DataSet") - test_class.assertEqual(len(datasets), len(vtu_file_name_list), f"file name = {pvd_file_name}, list_of_time_steps = {time_step_list}, list_of_vtu_files = \n" + "\n\t".join(vtu_file_name_list)) - for i, dataset in enumerate(datasets): - relative_path = Path(vtu_file_name_list[i]).absolute().relative_to(Path(pvd_file_name).absolute().parent) - test_class.assertEqual(dataset.get("file"), str(relative_path)) - test_class.assertEqual(dataset.get("name"), relative_path.name[:relative_path.name.rfind("_")]) - test_class.assertEqual(dataset.get("part"), str(i % (len(vtu_file_name_list) // len(time_step_list)))) - test_class.assertEqual(dataset.get("timestep"), f"{time_step_list[i // (len(vtu_file_name_list) // len(time_step_list))]:0.9e}", f"file name = {relative_path}") - kratos_utils.DeleteFileIfExisting(pvd_file_name) - - @staticmethod - def CheckGaussVtuFile(test_class: kratos_unittest.TestCase, model_part: Kratos.ModelPart, container, prefix: str, step_id: int, output_type: str, data_communicator: Kratos.DataCommunicator, point_fields): - number_of_points = 0 - for entity in container: - if len(entity.GetGeometry()) == 4: - number_of_points += 4 - elif len(entity.GetGeometry()) == 3: - number_of_points += 1 - elif len(entity.GetGeometry()) == 2: - number_of_points += 1 - else: - raise RuntimeError("Unsupported geometry") - - if isinstance(container, Kratos.ConditionsArray): - suffix = "condition" - elif isinstance(container, Kratos.ElementsArray): - suffix = "element" - else: - raise RuntimeError("Unsupported container type.") - - if data_communicator.IsDistributed(): - rank_suffix = f"_{data_communicator.Rank()}" - else: - rank_suffix = "" - - file_name = f"{prefix}/{model_part.FullName()}_{suffix}_gauss_{step_id}{rank_suffix}.vtu" - TestVtuOutput.CheckVtuFile( - test_class, - file_name, - number_of_points, None, output_type, point_fields, {}) - kratos_utils.DeleteFileIfExisting(file_name) - return file_name - - @staticmethod - def __GetUnstructuredGridList(unstructured_grid_list: 'list[tuple[Kratos.ModelPart, bool, typing.Optional[typing.Union[Kratos.ConditionsArray, Kratos.ElementsArray]]]]', model_part: Kratos.ModelPart, data_communicator: Kratos.DataCommunicator, recursively: bool) -> None: - availability = data_communicator.MaxAll(Kratos.Array3([model_part.NumberOfNodes(), model_part.NumberOfConditions(), model_part.NumberOfElements()])) - has_nodes = availability[0] > 0 - has_conditions = availability[1] > 0 - has_elements = availability[2] > 0 - - if has_elements: - unstructured_grid_list.append((model_part, has_nodes, model_part.Elements)) - - if has_conditions: - unstructured_grid_list.append((model_part, not has_elements and has_nodes, model_part.Conditions)) - - if not has_elements and not has_conditions: - unstructured_grid_list.append((model_part, has_nodes, None)) - - if recursively: - for sub_model_part in model_part.SubModelParts: - TestVtuOutput.__GetUnstructuredGridList(unstructured_grid_list, sub_model_part, data_communicator, recursively) - - @classmethod - def tearDownClass(cls): - kratos_utils.DeleteDirectoryIfExistingAndEmpty("temp") - - -if __name__ == "__main__": - Kratos.Logger.GetDefaultOutput().SetSeverity(Kratos.Logger.Severity.INFO) - kratos_unittest.main() \ No newline at end of file diff --git a/kratos/tests/test_vtu_output.py b/kratos/tests/test_vtu_output.py old mode 100644 new mode 100755 index 17680aa323f9..1b34d6009f6b --- a/kratos/tests/test_vtu_output.py +++ b/kratos/tests/test_vtu_output.py @@ -1,8 +1,10 @@ +import math, typing +from pathlib import Path +import xml.etree.ElementTree as ET import KratosMultiphysics as Kratos - -# Import KratosUnittest import KratosMultiphysics.KratosUnittest as kratos_unittest +import KratosMultiphysics.kratos_utilities as kratos_utils from KratosMultiphysics.compare_two_files_check_process import CompareTwoFilesCheckProcess from test_vtk_output_process import SetupModelPart2D, SetupModelPart3D @@ -14,45 +16,55 @@ def SetSolution(cls): node.SetSolutionStepValue(Kratos.VELOCITY, 0,[node.X * 5, node.Y * 6, node.Z * 7]) node.SetSolutionStepValue(Kratos.PRESSURE, 0, node.Id * 8.0) + elem: Kratos.Element for i_elem, elem in enumerate(cls.model_part.Elements): elem.SetValue(Kratos.DETERMINANT, [i_elem*0.189, i_elem * 1.236, i_elem * 2.365]) + cond: Kratos.Condition for i_cond, cond in enumerate(cls.model_part.Conditions): cond.SetValue(Kratos.DENSITY, i_cond * 4.362) cond.SetValue(Kratos.YOUNG_MODULUS, i_cond * 5.326) + cond.SetValue(Kratos.DETERMINANTS_OF_JACOBIAN_PARENT, Kratos.Vector()) @classmethod - def setUpClass(cls, output_prefix: str, setup_method) -> None: + def setUpClass(cls, output_prefix: str, setup_method, output_sub_model_parts: bool) -> None: cls.model = Kratos.Model() cls.model_part = cls.model.CreateModelPart("test") + cls.model_part.ProcessInfo[Kratos.STEP] = 0 + cls.model_part.ProcessInfo[Kratos.TIME] = 1.0 cls.output_prefix = output_prefix + cls.output_sub_model_parts = output_sub_model_parts setup_method(cls.model_part) cls.SetSolution() - def WriteVtu(self, output_format: Kratos.VtuOutput.WriterFormat): - vtu_output = Kratos.VtuOutput(self.model_part, True, output_format, 9) - vtu_output.AddHistoricalVariable(Kratos.PRESSURE) - vtu_output.AddHistoricalVariable(Kratos.VELOCITY) - vtu_output.AddHistoricalVariable(Kratos.DISPLACEMENT) - vtu_output.AddNonHistoricalVariable(Kratos.DETERMINANT, vtu_output.ELEMENTS) - - a = Kratos.Expression.NodalExpression(self.model_part) - Kratos.Expression.VariableExpressionIO.Read(a, Kratos.PRESSURE, True) - a *= 3 - vtu_output.AddContainerExpression("hist_exp", a) - - a = Kratos.Expression.ElementExpression(self.model_part) - Kratos.Expression.VariableExpressionIO.Read(a, Kratos.DETERMINANT) - a *= 3 - vtu_output.AddContainerExpression("elem_exp", a) - - with kratos_unittest.WorkFolderScope("./auxiliar_files_for_python_unittest/vtk_output_process_ref_files", __file__, True): - if output_format == Kratos.VtuOutput.ASCII: - output_file_prefix = "ascii" + self.output_prefix + "/Main" - else: - output_file_prefix = "binary" + self.output_prefix + "/Main" - vtu_output.PrintOutput(output_file_prefix + "_temp") - self.Check(output_file_prefix + "_temp.vtu", output_file_prefix + ".vtu") + def WriteVtu(self, output_format: Kratos.VtuOutput.WriterFormat, error_check = False): + vtu_output = Kratos.VtuOutput(self.model_part, True, output_format, 9, echo_level=0, output_sub_model_parts=self.output_sub_model_parts, write_ids=True) + vtu_output.AddVariable(Kratos.PRESSURE, Kratos.Globals.DataLocation.NodeHistorical) + vtu_output.AddVariable(Kratos.VELOCITY, Kratos.Globals.DataLocation.NodeHistorical) + vtu_output.AddVariable(Kratos.DISPLACEMENT, Kratos.Globals.DataLocation.NodeHistorical) + vtu_output.AddVariable(Kratos.DETERMINANT, Kratos.Globals.DataLocation.Element) + vtu_output.AddVariable(Kratos.DENSITY, Kratos.Globals.DataLocation.Condition) + vtu_output.AddVariable(Kratos.YOUNG_MODULUS, Kratos.Globals.DataLocation.Condition) + if error_check: + # adds a vector with zero size to check for the error. Because, in vtu lib, + # if the behavior is undefined if the "NumberOfComponents = 0". + vtu_output.AddVariable(Kratos.DETERMINANTS_OF_JACOBIAN_PARENT, Kratos.Globals.DataLocation.Condition) + + ta_1 = Kratos.TensorAdaptors.HistoricalVariableTensorAdaptor(self.model_part.Nodes, Kratos.PRESSURE) + ta_1.CollectData() + ta_2 = Kratos.TensorAdaptors.VariableTensorAdaptor(self.model_part.Elements, Kratos.DETERMINANT) + ta_2.CollectData() + + ta_1.data *= 3 + ta_2.data *= 3 + + vtu_output.AddTensorAdaptor("hist_ta", ta_1) + vtu_output.AddTensorAdaptor("elem_ta", ta_2) + + with kratos_unittest.WorkFolderScope("auxiliar_files_for_python_unittest/vtk_output_process_ref_files", __file__, True): + output_file_prefix = output_format.name.lower() + self.output_prefix + "/Main" + vtu_output.PrintOutput("temp/" + output_file_prefix) + self.Check("temp/" + output_file_prefix, output_file_prefix) def test_WriteMeshAscii(self): self.WriteVtu(Kratos.VtuOutput.ASCII) @@ -60,27 +72,510 @@ def test_WriteMeshAscii(self): def test_WriteMeshBinary(self): self.WriteVtu(Kratos.VtuOutput.BINARY) - def Check(self, output_file, reference_file): - ## Settings string in json format - params = Kratos.Parameters("""{ - "reference_file_name" : "", - "output_file_name" : "", - "comparison_type" : "deterministic" - }""") - params["reference_file_name"].SetString(reference_file) - params["output_file_name"].SetString(output_file) - CompareTwoFilesCheckProcess(params).Execute() + def test_WriteMeshRaw(self): + self.WriteVtu(Kratos.VtuOutput.RAW) + + def test_WriteMeshCompressedRaw(self): + self.WriteVtu(Kratos.VtuOutput.COMPRESSED_RAW) + + def test_WriteMeshAsciiWithError(self): + self.addCleanup(kratos_utils.DeleteDirectoryIfExisting, "auxiliar_files_for_python_unittest/vtk_output_process_ref_files/temp") + with self.assertRaises(RuntimeError): + self.WriteVtu(Kratos.VtuOutput.ASCII, True) + + def test_WriteMeshBinaryWithError(self): + self.addCleanup(kratos_utils.DeleteDirectoryIfExisting, "auxiliar_files_for_python_unittest/vtk_output_process_ref_files/temp") + with self.assertRaises(RuntimeError): + self.WriteVtu(Kratos.VtuOutput.BINARY, True) + + def test_WriteMeshRawWithError(self): + self.addCleanup(kratos_utils.DeleteDirectoryIfExisting, "auxiliar_files_for_python_unittest/vtk_output_process_ref_files/temp") + with self.assertRaises(RuntimeError): + self.WriteVtu(Kratos.VtuOutput.RAW, True) + + def test_WriteMeshCompressedRawWithError(self): + self.addCleanup(kratos_utils.DeleteDirectoryIfExisting, "auxiliar_files_for_python_unittest/vtk_output_process_ref_files/temp") + with self.assertRaises(RuntimeError): + self.WriteVtu(Kratos.VtuOutput.COMPRESSED_RAW, True) + + def Check(self, output_prefix, reference_prefix): + def check_file(output_file_name: str, reference_file_name: str): + ## Settings string in json format + params = Kratos.Parameters("""{ + "reference_file_name" : "", + "output_file_name" : "", + "comparison_type" : "deterministic" + }""") + params["reference_file_name"].SetString(reference_file_name) + params["output_file_name"].SetString(output_file_name) + CompareTwoFilesCheckProcess(params).Execute() + + for file_path in Path(reference_prefix).iterdir(): + self.assertTrue((Path(output_prefix) / file_path.name).is_file(), msg=f"\"{(Path(output_prefix) / file_path.name)}\" is not a file.") + check_file(f"{output_prefix}/{file_path.name}", str(file_path)) + check_file(f"{output_prefix}.pvd", f"{reference_prefix}.pvd") + + kratos_utils.DeleteDirectoryIfExistingAndEmpty("temp") class TestVtuOutput2D(TestVtuOutputBase, kratos_unittest.TestCase): @classmethod def setUpClass(cls) -> None: - super().setUpClass("2D", SetupModelPart2D) + super().setUpClass("2D", SetupModelPart2D, output_sub_model_parts = True) class TestVtuOutput3D(TestVtuOutputBase, kratos_unittest.TestCase): @classmethod def setUpClass(cls) -> None: - super().setUpClass("3D", SetupModelPart3D) + # the method SetupModelPart3D does not create sub model parts + # with nodes which do not include nodes from its conditions or elements. It uses + # some random nodes. Hence sub_model_part output is disabled. + super().setUpClass("3D", SetupModelPart3D, output_sub_model_parts = False) + +class TestVtuOutput(kratos_unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.data_location = Kratos.Globals.DataLocation + + cls.model = Kratos.Model() + cls.model_part = cls.model.CreateModelPart("test") + cls.model_part.AddNodalSolutionStepVariable(Kratos.STEP) + cls.model_part.AddNodalSolutionStepVariable(Kratos.PRESSURE) + cls.model_part.AddNodalSolutionStepVariable(Kratos.DISPLACEMENT) + cls.model_part.AddNodalSolutionStepVariable(Kratos.DETERMINANTS_OF_JACOBIAN_PARENT) + cls.model_part.AddNodalSolutionStepVariable(Kratos.CONSTITUTIVE_MATRIX) + + cls.model_part.ProcessInfo[Kratos.TIME] = 1 + + # creating a circular pie with origin (0, 0) + radius = 1.0 + number_of_elements_or_conditions = 50 + angle = 2 * math.pi / number_of_elements_or_conditions + + cls.model_part.CreateNewNode(1, 0, 0, 0) # origin node + for i in range(number_of_elements_or_conditions): + theta = i * angle + cls.model_part.CreateNewNode(i + 2, radius * math.cos(theta), radius * math.sin(theta), 0.0) + + prop = cls.model_part.CreateNewProperties(1) + for i in range(number_of_elements_or_conditions): + cls.model_part.CreateNewElement("Element2D3N", i + 1, [1, i + 2, (i + 1) % (number_of_elements_or_conditions) + 2], prop) + cls.model_part.CreateNewCondition("LineCondition2D2N", i + 1, [i + 2, (i + 1) % (number_of_elements_or_conditions) + 2], prop) + + # create the sub model part structure + for j in range(4): + l_1 = j // 9 + l_2 = (j // 3) % 3 + l_3 = j % 3 + model_part = cls.model_part.CreateSubModelPart(f"mp_{l_1}.mp_{l_2}.mp_{l_3}") + # fill the sub range + for i in range(number_of_elements_or_conditions): + if (j % 2 == 0): + if (i % ((l_1 + 1) * (l_2 + 1) * (l_3 + 1)) == 0): + model_part.AddCondition(cls.model_part.GetCondition(i + 1)) + else: + if (i % ((l_1 + 1) * (l_2 + 1) * (l_3 + 1)) == 1): + model_part.AddElement(cls.model_part.GetElement(i + 1)) + + # now recursively fill the nodes + def fill_nodes(model_part: Kratos.ModelPart): + list_of_node_ids: 'list[int]' = [] + for condition in model_part.Conditions: + for node in condition.GetGeometry(): + list_of_node_ids.append(node.Id) + for element in model_part.Elements: + for node in element.GetGeometry(): + list_of_node_ids.append(node.Id) + + model_part.AddNodes(list_of_node_ids) + + for sub_model_part in model_part.SubModelParts: + fill_nodes(sub_model_part) + + fill_nodes(cls.model_part) + + def add_variables(container, setter): + for entity in container: + setter(entity, Kratos.STEP, entity.Id * 2) + setter(entity, Kratos.PRESSURE, entity.Id) + setter(entity, Kratos.DISPLACEMENT, Kratos.Array3([entity.Id, entity.Id + 1, entity.Id + 2])) + setter(entity, Kratos.DETERMINANTS_OF_JACOBIAN_PARENT, Kratos.Vector([entity.Id, entity.Id + 1, entity.Id + 2, entity.Id + 3, entity.Id + 4])) + setter(entity, Kratos.CONSTITUTIVE_MATRIX, Kratos.Matrix([[entity.Id, entity.Id + 1], [entity.Id + 2, entity.Id + 3], [entity.Id + 4, entity.Id + 5]])) + + add_variables(cls.model_part.Nodes, lambda x, y, z: x.SetSolutionStepValue(y, z)) + add_variables(cls.model_part.Nodes, lambda x, y, z: x.SetValue(y, z)) + add_variables(cls.model_part.Conditions, lambda x, y, z: x.SetValue(y, z)) + add_variables(cls.model_part.Elements, lambda x, y, z: x.SetValue(y, z)) + + def setUp(self): + self.model_part.ProcessInfo[Kratos.STEP] = 0 + + def test_GetOutputContainerList(self): + unstructured_grid_list = self.GetUnstructuredGridList(self.model_part, self.model_part.GetRootModelPart().GetCommunicator().GetDataCommunicator(), True) + + vtu_output = Kratos.VtuOutput(self.model_part, output_sub_model_parts=True, output_format=Kratos.VtuOutput.BINARY) + list_of_containers = vtu_output.GetOutputContainerList() + + list_of_ref_containers = [] + for mp, is_nodes_used, cells_container in unstructured_grid_list: + if is_nodes_used: + list_of_ref_containers.append(mp.Nodes) + list_of_ref_containers.append(mp.GetCommunicator().LocalMesh().Nodes) + + if cells_container is not None: + list_of_ref_containers.append(cells_container) + if isinstance(cells_container, Kratos.ConditionsArray): + list_of_ref_containers.append(mp.GetCommunicator().LocalMesh().Conditions) + elif isinstance(cells_container, Kratos.ElementsArray): + list_of_ref_containers.append(mp.GetCommunicator().LocalMesh().Elements) + + self.assertEqual(list_of_containers, list_of_ref_containers) + + def test_PointVariableAddition(self): + vtu_output = Kratos.VtuOutput(self.model_part, output_sub_model_parts=True, output_format=Kratos.VtuOutput.BINARY) + vtu_output.AddVariable(Kratos.PRESSURE, self.data_location.NodeHistorical) + vtu_output.AddVariable(Kratos.PRESSURE, self.data_location.Condition) + vtu_output.AddVariable(Kratos.PRESSURE, self.data_location.Element) + vtu_output.AddIntegrationPointVariable(Kratos.PRESSURE, self.data_location.Condition) + vtu_output.AddIntegrationPointVariable(Kratos.PRESSURE, self.data_location.Element) + + with self.assertRaises(RuntimeError): + vtu_output.AddVariable(Kratos.PRESSURE, self.data_location.NodeHistorical) + + with self.assertRaises(RuntimeError): + vtu_output.AddVariable(Kratos.PRESSURE, self.data_location.NodeNonHistorical) + + ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(self.model_part.Nodes, Kratos.DoubleNDData([51, 5])) + ta.Check() + with self.assertRaises(RuntimeError): + vtu_output.AddTensorAdaptor("PRESSURE", ta) + vtu_output.AddTensorAdaptor("PRESSURE_1", ta) + + with self.assertRaises(RuntimeError): + vtu_output.AddTensorAdaptor("PRESSURE_1", ta) + vtu_output.AddTensorAdaptor("PRESSURE_2", ta) + + ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(self.model_part.Conditions, Kratos.DoubleNDData([50,2,4])) + ta.Check() + with self.assertRaises(RuntimeError): + vtu_output.AddTensorAdaptor("PRESSURE", ta) + vtu_output.AddTensorAdaptor("PRESSURE_1", ta) + vtu_output.AddTensorAdaptor("PRESSURE_2", ta) + vtu_output.AddTensorAdaptor("PRESSURE_3", ta) + + ta = Kratos.TensorAdaptors.DoubleTensorAdaptor(self.model_part.Elements, Kratos.DoubleNDData([50,2,5])) + ta.Check() + with self.assertRaises(RuntimeError): + vtu_output.AddTensorAdaptor("PRESSURE", ta) + vtu_output.AddTensorAdaptor("PRESSURE_1", ta) + vtu_output.AddTensorAdaptor("PRESSURE_2", ta) + vtu_output.AddTensorAdaptor("PRESSURE_3", ta) + + vtu_output.PrintOutput("temp/vtu_output/variable_test") + + model_part = vtu_output.GetModelPart() + unstructured_grid_list = self.GetUnstructuredGridList(model_part, model_part.GetCommunicator().GetDataCommunicator(), True) + list_of_vtu_file_names: 'list[str]' = [] + for model_part, use_nodes, container in unstructured_grid_list: + vtu_file_name = TestVtuOutput.GetUnstructuredGridName((model_part, use_nodes, container), "temp/vtu_output/variable_test", 0, model_part.GetCommunicator().GetDataCommunicator()) + list_of_vtu_file_names.append(vtu_file_name) + if model_part.FullName() == "test": + if use_nodes: + TestVtuOutput.CheckVtuFile(self, vtu_file_name, model_part.NumberOfNodes(), len(container), "binary", + { + "PRESSURE": (1, "Float64"), + "PRESSURE_1": (5, "Float64"), + "PRESSURE_2": (5, "Float64") + }, + { + "PRESSURE": (1, "Float64") + }) + elif isinstance(container, Kratos.ConditionsArray): + TestVtuOutput.CheckVtuFile(self, vtu_file_name, TestVtuOutput.GetNumberOfNodes(container), len(container), "binary", + {}, + { + "PRESSURE": (1, "Float64"), + "PRESSURE_1": (8, "Float64"), + "PRESSURE_2": (8, "Float64"), + "PRESSURE_3": (8, "Float64") + }) + elif isinstance(container, Kratos.ElementsArray): + TestVtuOutput.CheckVtuFile(self, vtu_file_name, TestVtuOutput.GetNumberOfNodes(container), len(container), "binary", + { + "PRESSURE": (1, "Float64"), + "PRESSURE_1": (5, "Float64"), + "PRESSURE_2": (1, "Float64"), + "PRESSURE_3": (5, "Float64") + }, + { + "PRESSURE": (1, "Float64"), + "PRESSURE_1": (10, "Float64"), + "PRESSURE_2": (10, "Float64"), + "PRESSURE_3": (10, "Float64") + }) + else: + if use_nodes: + TestVtuOutput.CheckVtuFile(self, vtu_file_name, model_part.NumberOfNodes(), len(container), "binary", + { + "PRESSURE": (1, "Float64") + }, + { + "PRESSURE": (1, "Float64") + }) + else: + TestVtuOutput.CheckVtuFile(self, vtu_file_name, TestVtuOutput.GetNumberOfNodes(container), len(container), "binary", + { + }, + { + "PRESSURE": (1, "Float64") + }) + # check gauss + list_of_vtu_file_names.append(TestVtuOutput.CheckGaussVtuFile(self, model_part, container, "temp/vtu_output/variable_test", 0, "binary", model_part.GetCommunicator().GetDataCommunicator(), + { + "PRESSURE": (1, "Float64") + })) + TestVtuOutput.CheckPvdFile(self, "temp/vtu_output/variable_test.pvd", list_of_vtu_file_names, [1 + 1e-9]) + + def test_CellVariableAddition(self): + vtu_output = Kratos.VtuOutput(self.model_part, output_format=Kratos.VtuOutput.ASCII, output_sub_model_parts=True) + vtu_output.AddVariable(Kratos.PRESSURE, self.data_location.Condition) + vtu_output.AddVariable(Kratos.PRESSURE, self.data_location.NodeHistorical) + vtu_output.AddVariable(Kratos.PRESSURE, self.data_location.Element) + vtu_output.AddIntegrationPointVariable(Kratos.PRESSURE, self.data_location.Condition) + vtu_output.AddIntegrationPointVariable(Kratos.PRESSURE, self.data_location.Element) + + vtu_output.AddVariable(Kratos.DISPLACEMENT, self.data_location.Element) + vtu_output.AddVariable(Kratos.DISPLACEMENT, self.data_location.NodeHistorical) + vtu_output.AddVariable(Kratos.DISPLACEMENT, self.data_location.Condition) + vtu_output.AddIntegrationPointVariable(Kratos.DISPLACEMENT, self.data_location.Condition) + vtu_output.AddIntegrationPointVariable(Kratos.DISPLACEMENT, self.data_location.Element) + + vtu_output.PrintOutput("temp/vtu_output/time_step_test") + vtu_output.GetModelPart().ProcessInfo[Kratos.TIME] += 1e-9 + vtu_output.GetModelPart().ProcessInfo[Kratos.STEP] += 1 + vtu_output.PrintOutput("temp/vtu_output/time_step_test") + + model_part = vtu_output.GetModelPart() + unstructured_grid_list = self.GetUnstructuredGridList(model_part, model_part.GetCommunicator().GetDataCommunicator(), True) + list_of_vtu_file_names: 'list[str]' = [] + for step in range(2): + for model_part, use_nodes, container in unstructured_grid_list: + vtu_file_name = TestVtuOutput.GetUnstructuredGridName((model_part, use_nodes, container), "temp/vtu_output/time_step_test", step, model_part.GetCommunicator().GetDataCommunicator()) + list_of_vtu_file_names.append(vtu_file_name) + if use_nodes: + TestVtuOutput.CheckVtuFile(self, vtu_file_name, model_part.NumberOfNodes(), len(container), "ascii", + { + "PRESSURE": (1, "Float64"), + "DISPLACEMENT": (3, "Float64") + }, + { + "PRESSURE": (1, "Float64"), + "DISPLACEMENT": (3, "Float64") + }) + else: + TestVtuOutput.CheckVtuFile(self, vtu_file_name, TestVtuOutput.GetNumberOfNodes(container), len(container), "ascii", + { + }, + { + "PRESSURE": (1, "Float64"), + "DISPLACEMENT": (3, "Float64") + }) + + # check gauss + list_of_vtu_file_names.append(TestVtuOutput.CheckGaussVtuFile(self, model_part, container, "temp/vtu_output/time_step_test", step, "ascii", model_part.GetCommunicator().GetDataCommunicator(), + { + "DISPLACEMENT": (3, "Float64") + })) + + TestVtuOutput.CheckPvdFile(self, "temp/vtu_output/time_step_test.pvd", list_of_vtu_file_names, [1, 1 + 1e-9]) + + @staticmethod + def GetUnstructuredGridList(model_part: Kratos.ModelPart, data_communicator: Kratos.DataCommunicator, recursively: bool) -> 'list[tuple[Kratos.ModelPart, bool, typing.Optional[typing.Union[Kratos.ConditionsArray, Kratos.ElementsArray]]]]': + unstructured_grid_list: 'list[tuple[Kratos.ModelPart, bool, typing.Optional[typing.Union[Kratos.ConditionsArray, Kratos.ElementsArray]]]]' = [] + TestVtuOutput.__GetUnstructuredGridList(unstructured_grid_list, model_part, data_communicator, recursively) + return sorted(unstructured_grid_list, key = lambda x: x[0].FullName()) + + @staticmethod + def GetUnstructuredGridName(unstructured_grid: 'tuple[Kratos.ModelPart, bool, typing.Optional[typing.Union[Kratos.ConditionsArray, Kratos.ElementsArray]]]', prefix: str, step: int, data_communicator: Kratos.DataCommunicator, entity_suffix = "s") -> str: + if data_communicator.IsDistributed(): + rank_suffix = f"_{data_communicator.Rank()}" + else: + rank_suffix = "" + + if unstructured_grid[2] is None: + entity_type = "node" + elif isinstance(unstructured_grid[2], Kratos.ConditionsArray): + entity_type = "condition" + elif isinstance(unstructured_grid[2], Kratos.ElementsArray): + entity_type = "element" + return f"{prefix}/{unstructured_grid[0].FullName()}_{entity_type}{entity_suffix}_{step}{rank_suffix}.vtu" + + @staticmethod + def GetNodes(model_part: Kratos.ModelPart, use_model_part_nodes: bool, container: 'typing.Union[Kratos.ConditionsArray, Kratos.ElementsArray]') -> 'list[Kratos.Node]': + if use_model_part_nodes: + return model_part.Nodes + else: + temp = [] + for entity in container: + for node in entity.GetGeometry(): + temp.append(node.Id) + return [model_part.GetRootModelPart().GetNode(node_id) for node_id in list(sorted(set(temp)))] + + def GetNumberOfNodes(container: 'typing.Union[Kratos.ConditionsArray, Kratos.ElementsArray]') -> int: + temp = [] + for entity in container: + for node in entity.GetGeometry(): + temp.append(node.Id) + return len(list(set(temp))) + + @staticmethod + def CheckDataArray(test_class: kratos_unittest.TestCase, xml_element: ET.Element, number_of_components: int, name: str, data_type: str, data_format: 'typing.Optional[str]' = None): + test_class.assertEqual(xml_element.get("NumberOfComponents"), str(number_of_components)) + test_class.assertEqual(xml_element.get("type"), data_type) + test_class.assertEqual(xml_element.get("Name"), name) + if data_format is not None: + test_class.assertEqual(xml_element.get("format"), data_format) + + @staticmethod + def CheckVtuFile( + test_class: kratos_unittest.TestCase, + vtu_file_name: str, + number_of_points: int, + number_of_cells: 'typing.Optional[int]', + data_format : str, + point_data_fields: 'dict[str, tuple[int, str]]', + cell_data_fields: 'dict[str, tuple[int, str]]'): + + test_class.assertTrue(Path(vtu_file_name).is_file(), f"The file {vtu_file_name} not found.") + tree = ET.parse(vtu_file_name) + root = tree.getroot() + + test_class.assertEqual(root.tag, "VTKFile") + test_class.assertEqual(root.get("type"), "UnstructuredGrid") + test_class.assertEqual(root.get("version"), "0.1") + + unstructured_grid = root.find("UnstructuredGrid") + piece = unstructured_grid.find("Piece") + + if number_of_cells is None: + local_number_of_cells = 0 + else: + local_number_of_cells = number_of_cells + + test_class.assertEqual(piece.get("NumberOfPoints"), f"{number_of_points}", f"Vtu file name = {vtu_file_name}") + test_class.assertEqual(piece.get("NumberOfCells"), f"{local_number_of_cells}", f"Vtu file name = {vtu_file_name}") + + points = piece.find("Points") + TestVtuOutput.CheckDataArray(test_class, points.find("DataArray"), 3, "Position", "Float64", data_format) + + cells = piece.find("Cells") + if not number_of_cells is None: + data_arrays = cells.findall("DataArray") + TestVtuOutput.CheckDataArray(test_class, data_arrays[0], 1, "connectivity", "Int32", data_format) + TestVtuOutput.CheckDataArray(test_class, data_arrays[1], 1, "offsets", "Int32", data_format) + TestVtuOutput.CheckDataArray(test_class, data_arrays[2], 1, "types", "UInt8", data_format) + + # now checking for point data + point_data = piece.find("PointData") + for data_field_name, (data_field_number_of_components, data_field_data_type) in point_data_fields.items(): + found = False + for point_data_array in point_data.findall("DataArray"): + if point_data_array.get("Name") == data_field_name: + TestVtuOutput.CheckDataArray(test_class, point_data_array, data_field_number_of_components, data_field_name, data_field_data_type, data_format) + found = True + break + test_class.assertTrue(found, f"Point data field \"{data_field_name}\" not found in the \"{vtu_file_name}\"") + + if not number_of_cells is None: + # now checking for cell data + cell_data = piece.find("CellData") + for data_field_name, (data_field_number_of_components, data_field_data_type) in cell_data_fields.items(): + found = False + for point_data_array in cell_data.findall("DataArray"): + if point_data_array.get("Name") == data_field_name: + TestVtuOutput.CheckDataArray(test_class, point_data_array, data_field_number_of_components, data_field_name, data_field_data_type, data_format) + found = True + break + test_class.assertTrue(found, f"Cell data field \"{data_field_name}\" not found in the \"{vtu_file_name}\"") + kratos_utils.DeleteFileIfExisting(vtu_file_name) + + @staticmethod + def CheckPvdFile(test_class: kratos_unittest.TestCase, pvd_file_name: str, vtu_file_name_list: 'list[str]', time_step_list: 'list[float]'): + test_class.assertTrue(Path(pvd_file_name).is_file(), f"The file {pvd_file_name} not found.") + tree = ET.parse(pvd_file_name) + root = tree.getroot() + + test_class.assertEqual(root.tag, "VTKFile") + test_class.assertEqual(root.get("type"), "Collection") + test_class.assertEqual(root.get("version"), "1.0") + + collection = root.find("Collection") + datasets = collection.findall("DataSet") + test_class.assertEqual(len(datasets), len(vtu_file_name_list), f"file name = {pvd_file_name}, list_of_time_steps = {time_step_list}, list_of_vtu_files = \n" + "\n\t".join(vtu_file_name_list)) + for i, dataset in enumerate(datasets): + relative_path = Path(vtu_file_name_list[i]).absolute().relative_to(Path(pvd_file_name).absolute().parent) + test_class.assertEqual(dataset.get("file"), str(relative_path)) + test_class.assertEqual(dataset.get("name"), relative_path.name[:relative_path.name.rfind("_")]) + test_class.assertEqual(dataset.get("part"), str(i % (len(vtu_file_name_list) // len(time_step_list)))) + test_class.assertEqual(dataset.get("timestep"), f"{time_step_list[i // (len(vtu_file_name_list) // len(time_step_list))]:0.9e}", f"file name = {relative_path}") + kratos_utils.DeleteFileIfExisting(pvd_file_name) + + @staticmethod + def CheckGaussVtuFile(test_class: kratos_unittest.TestCase, model_part: Kratos.ModelPart, container, prefix: str, step_id: int, output_type: str, data_communicator: Kratos.DataCommunicator, point_fields): + number_of_points = 0 + for entity in container: + if len(entity.GetGeometry()) == 4: + number_of_points += 4 + elif len(entity.GetGeometry()) == 3: + number_of_points += 1 + elif len(entity.GetGeometry()) == 2: + number_of_points += 1 + else: + raise RuntimeError("Unsupported geometry") + + if isinstance(container, Kratos.ConditionsArray): + suffix = "condition" + elif isinstance(container, Kratos.ElementsArray): + suffix = "element" + else: + raise RuntimeError("Unsupported container type.") + + if data_communicator.IsDistributed(): + rank_suffix = f"_{data_communicator.Rank()}" + else: + rank_suffix = "" + + file_name = f"{prefix}/{model_part.FullName()}_{suffix}_gauss_{step_id}{rank_suffix}.vtu" + TestVtuOutput.CheckVtuFile( + test_class, + file_name, + number_of_points, None, output_type, point_fields, {}) + kratos_utils.DeleteFileIfExisting(file_name) + return file_name + + @staticmethod + def __GetUnstructuredGridList(unstructured_grid_list: 'list[tuple[Kratos.ModelPart, bool, typing.Optional[typing.Union[Kratos.ConditionsArray, Kratos.ElementsArray]]]]', model_part: Kratos.ModelPart, data_communicator: Kratos.DataCommunicator, recursively: bool) -> None: + availability = data_communicator.MaxAll(Kratos.Array3([model_part.NumberOfNodes(), model_part.NumberOfConditions(), model_part.NumberOfElements()])) + has_nodes = availability[0] > 0 + has_conditions = availability[1] > 0 + has_elements = availability[2] > 0 + + if has_elements: + unstructured_grid_list.append((model_part, has_nodes, model_part.Elements)) + + if has_conditions: + unstructured_grid_list.append((model_part, not has_elements and has_nodes, model_part.Conditions)) + + if not has_elements and not has_conditions: + unstructured_grid_list.append((model_part, has_nodes, None)) + + if recursively: + for sub_model_part in model_part.SubModelParts: + TestVtuOutput.__GetUnstructuredGridList(unstructured_grid_list, sub_model_part, data_communicator, recursively) + + @classmethod + def tearDownClass(cls): + kratos_utils.DeleteDirectoryIfExistingAndEmpty("temp") + if __name__ == "__main__": - Kratos.Logger.GetDefaultOutput().SetSeverity(Kratos.Logger.Severity.WARNING) + Kratos.Logger.GetDefaultOutput().SetSeverity(Kratos.Logger.Severity.INFO) kratos_unittest.main() \ No newline at end of file From 3941cd72f80571ff15f522594418da58e4c5350c Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 20 Feb 2026 08:19:35 +0100 Subject: [PATCH 107/116] move test files --- .../vtk_output_process_ref_files/ascii2D/Main.pvd | 0 .../Main/test.FixedEdgeNodes_conditions_0.vtu | 0 .../ascii2D/Main/test.MovingNodes_conditions_0.vtu | 0 .../ascii2D/Main/test_conditions_0.vtu | 0 .../ascii2D/Main/test_elements_0.vtu | 0 .../vtk_output_process_ref_files/ascii3D/Main.pvd | 0 .../ascii3D/Main/test_conditions_0.vtu | 0 .../ascii3D/Main/test_elements_0.vtu | 0 .../vtk_output_process_ref_files/binary2D/Main.pvd | 0 .../Main/test.FixedEdgeNodes_conditions_0.vtu | 0 .../binary2D/Main/test.MovingNodes_conditions_0.vtu | 0 .../binary2D/Main/test_conditions_0.vtu | 0 .../binary2D/Main/test_elements_0.vtu | 0 .../vtk_output_process_ref_files/binary3D/Main.pvd | 0 .../binary3D/Main/test_conditions_0.vtu | 0 .../binary3D/Main/test_elements_0.vtu | 0 .../compressed_raw2D/Main.pvd | 0 .../Main/test.FixedEdgeNodes_conditions_0.vtu | Bin .../Main/test.MovingNodes_conditions_0.vtu | Bin .../compressed_raw2D/Main/test_conditions_0.vtu | Bin .../compressed_raw2D/Main/test_elements_0.vtu | Bin .../compressed_raw3D/Main.pvd | 0 .../compressed_raw3D/Main/test_conditions_0.vtu | Bin .../compressed_raw3D/Main/test_elements_0.vtu | Bin .../vtk_output_process_ref_files/raw2D/Main.pvd | 0 .../raw2D/Main/test.FixedEdgeNodes_conditions_0.vtu | Bin .../raw2D/Main/test.MovingNodes_conditions_0.vtu | Bin .../raw2D/Main/test_conditions_0.vtu | Bin .../raw2D/Main/test_elements_0.vtu | Bin .../vtk_output_process_ref_files/raw3D/Main.pvd | 0 .../raw3D/Main/test_conditions_0.vtu | Bin .../raw3D/Main/test_elements_0.vtu | Bin 32 files changed, 0 insertions(+), 0 deletions(-) rename kratos/{future/tests => tests/auxiliar_files_for_python_unittest}/vtk_output_process_ref_files/ascii2D/Main.pvd (100%) mode change 100644 => 100755 rename kratos/{future/tests => tests/auxiliar_files_for_python_unittest}/vtk_output_process_ref_files/ascii2D/Main/test.FixedEdgeNodes_conditions_0.vtu (100%) mode change 100644 => 100755 rename kratos/{future/tests => tests/auxiliar_files_for_python_unittest}/vtk_output_process_ref_files/ascii2D/Main/test.MovingNodes_conditions_0.vtu (100%) mode change 100644 => 100755 rename kratos/{future/tests => tests/auxiliar_files_for_python_unittest}/vtk_output_process_ref_files/ascii2D/Main/test_conditions_0.vtu (100%) mode change 100644 => 100755 rename kratos/{future/tests => tests/auxiliar_files_for_python_unittest}/vtk_output_process_ref_files/ascii2D/Main/test_elements_0.vtu (100%) mode change 100644 => 100755 rename kratos/{future/tests => tests/auxiliar_files_for_python_unittest}/vtk_output_process_ref_files/ascii3D/Main.pvd (100%) mode change 100644 => 100755 rename kratos/{future/tests => tests/auxiliar_files_for_python_unittest}/vtk_output_process_ref_files/ascii3D/Main/test_conditions_0.vtu (100%) mode change 100644 => 100755 rename kratos/{future/tests => tests/auxiliar_files_for_python_unittest}/vtk_output_process_ref_files/ascii3D/Main/test_elements_0.vtu (100%) mode change 100644 => 100755 rename kratos/{future/tests => tests/auxiliar_files_for_python_unittest}/vtk_output_process_ref_files/binary2D/Main.pvd (100%) mode change 100644 => 100755 rename kratos/{future/tests => tests/auxiliar_files_for_python_unittest}/vtk_output_process_ref_files/binary2D/Main/test.FixedEdgeNodes_conditions_0.vtu (100%) mode change 100644 => 100755 rename kratos/{future/tests => tests/auxiliar_files_for_python_unittest}/vtk_output_process_ref_files/binary2D/Main/test.MovingNodes_conditions_0.vtu (100%) mode change 100644 => 100755 rename kratos/{future/tests => tests/auxiliar_files_for_python_unittest}/vtk_output_process_ref_files/binary2D/Main/test_conditions_0.vtu (100%) mode change 100644 => 100755 rename kratos/{future/tests => tests/auxiliar_files_for_python_unittest}/vtk_output_process_ref_files/binary2D/Main/test_elements_0.vtu (100%) mode change 100644 => 100755 rename kratos/{future/tests => tests/auxiliar_files_for_python_unittest}/vtk_output_process_ref_files/binary3D/Main.pvd (100%) mode change 100644 => 100755 rename kratos/{future/tests => tests/auxiliar_files_for_python_unittest}/vtk_output_process_ref_files/binary3D/Main/test_conditions_0.vtu (100%) mode change 100644 => 100755 rename kratos/{future/tests => tests/auxiliar_files_for_python_unittest}/vtk_output_process_ref_files/binary3D/Main/test_elements_0.vtu (100%) mode change 100644 => 100755 rename kratos/{future/tests => tests/auxiliar_files_for_python_unittest}/vtk_output_process_ref_files/compressed_raw2D/Main.pvd (100%) mode change 100644 => 100755 rename kratos/{future/tests => tests/auxiliar_files_for_python_unittest}/vtk_output_process_ref_files/compressed_raw2D/Main/test.FixedEdgeNodes_conditions_0.vtu (100%) mode change 100644 => 100755 rename kratos/{future/tests => tests/auxiliar_files_for_python_unittest}/vtk_output_process_ref_files/compressed_raw2D/Main/test.MovingNodes_conditions_0.vtu (100%) mode change 100644 => 100755 rename kratos/{future/tests => tests/auxiliar_files_for_python_unittest}/vtk_output_process_ref_files/compressed_raw2D/Main/test_conditions_0.vtu (100%) mode change 100644 => 100755 rename kratos/{future/tests => tests/auxiliar_files_for_python_unittest}/vtk_output_process_ref_files/compressed_raw2D/Main/test_elements_0.vtu (100%) mode change 100644 => 100755 rename kratos/{future/tests => tests/auxiliar_files_for_python_unittest}/vtk_output_process_ref_files/compressed_raw3D/Main.pvd (100%) mode change 100644 => 100755 rename kratos/{future/tests => tests/auxiliar_files_for_python_unittest}/vtk_output_process_ref_files/compressed_raw3D/Main/test_conditions_0.vtu (100%) mode change 100644 => 100755 rename kratos/{future/tests => tests/auxiliar_files_for_python_unittest}/vtk_output_process_ref_files/compressed_raw3D/Main/test_elements_0.vtu (100%) mode change 100644 => 100755 rename kratos/{future/tests => tests/auxiliar_files_for_python_unittest}/vtk_output_process_ref_files/raw2D/Main.pvd (100%) mode change 100644 => 100755 rename kratos/{future/tests => tests/auxiliar_files_for_python_unittest}/vtk_output_process_ref_files/raw2D/Main/test.FixedEdgeNodes_conditions_0.vtu (100%) mode change 100644 => 100755 rename kratos/{future/tests => tests/auxiliar_files_for_python_unittest}/vtk_output_process_ref_files/raw2D/Main/test.MovingNodes_conditions_0.vtu (100%) mode change 100644 => 100755 rename kratos/{future/tests => tests/auxiliar_files_for_python_unittest}/vtk_output_process_ref_files/raw2D/Main/test_conditions_0.vtu (100%) mode change 100644 => 100755 rename kratos/{future/tests => tests/auxiliar_files_for_python_unittest}/vtk_output_process_ref_files/raw2D/Main/test_elements_0.vtu (100%) mode change 100644 => 100755 rename kratos/{future/tests => tests/auxiliar_files_for_python_unittest}/vtk_output_process_ref_files/raw3D/Main.pvd (100%) mode change 100644 => 100755 rename kratos/{future/tests => tests/auxiliar_files_for_python_unittest}/vtk_output_process_ref_files/raw3D/Main/test_conditions_0.vtu (100%) mode change 100644 => 100755 rename kratos/{future/tests => tests/auxiliar_files_for_python_unittest}/vtk_output_process_ref_files/raw3D/Main/test_elements_0.vtu (100%) mode change 100644 => 100755 diff --git a/kratos/future/tests/vtk_output_process_ref_files/ascii2D/Main.pvd b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/ascii2D/Main.pvd old mode 100644 new mode 100755 similarity index 100% rename from kratos/future/tests/vtk_output_process_ref_files/ascii2D/Main.pvd rename to kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/ascii2D/Main.pvd diff --git a/kratos/future/tests/vtk_output_process_ref_files/ascii2D/Main/test.FixedEdgeNodes_conditions_0.vtu b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/ascii2D/Main/test.FixedEdgeNodes_conditions_0.vtu old mode 100644 new mode 100755 similarity index 100% rename from kratos/future/tests/vtk_output_process_ref_files/ascii2D/Main/test.FixedEdgeNodes_conditions_0.vtu rename to kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/ascii2D/Main/test.FixedEdgeNodes_conditions_0.vtu diff --git a/kratos/future/tests/vtk_output_process_ref_files/ascii2D/Main/test.MovingNodes_conditions_0.vtu b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/ascii2D/Main/test.MovingNodes_conditions_0.vtu old mode 100644 new mode 100755 similarity index 100% rename from kratos/future/tests/vtk_output_process_ref_files/ascii2D/Main/test.MovingNodes_conditions_0.vtu rename to kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/ascii2D/Main/test.MovingNodes_conditions_0.vtu diff --git a/kratos/future/tests/vtk_output_process_ref_files/ascii2D/Main/test_conditions_0.vtu b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/ascii2D/Main/test_conditions_0.vtu old mode 100644 new mode 100755 similarity index 100% rename from kratos/future/tests/vtk_output_process_ref_files/ascii2D/Main/test_conditions_0.vtu rename to kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/ascii2D/Main/test_conditions_0.vtu diff --git a/kratos/future/tests/vtk_output_process_ref_files/ascii2D/Main/test_elements_0.vtu b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/ascii2D/Main/test_elements_0.vtu old mode 100644 new mode 100755 similarity index 100% rename from kratos/future/tests/vtk_output_process_ref_files/ascii2D/Main/test_elements_0.vtu rename to kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/ascii2D/Main/test_elements_0.vtu diff --git a/kratos/future/tests/vtk_output_process_ref_files/ascii3D/Main.pvd b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/ascii3D/Main.pvd old mode 100644 new mode 100755 similarity index 100% rename from kratos/future/tests/vtk_output_process_ref_files/ascii3D/Main.pvd rename to kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/ascii3D/Main.pvd diff --git a/kratos/future/tests/vtk_output_process_ref_files/ascii3D/Main/test_conditions_0.vtu b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/ascii3D/Main/test_conditions_0.vtu old mode 100644 new mode 100755 similarity index 100% rename from kratos/future/tests/vtk_output_process_ref_files/ascii3D/Main/test_conditions_0.vtu rename to kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/ascii3D/Main/test_conditions_0.vtu diff --git a/kratos/future/tests/vtk_output_process_ref_files/ascii3D/Main/test_elements_0.vtu b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/ascii3D/Main/test_elements_0.vtu old mode 100644 new mode 100755 similarity index 100% rename from kratos/future/tests/vtk_output_process_ref_files/ascii3D/Main/test_elements_0.vtu rename to kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/ascii3D/Main/test_elements_0.vtu diff --git a/kratos/future/tests/vtk_output_process_ref_files/binary2D/Main.pvd b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/binary2D/Main.pvd old mode 100644 new mode 100755 similarity index 100% rename from kratos/future/tests/vtk_output_process_ref_files/binary2D/Main.pvd rename to kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/binary2D/Main.pvd diff --git a/kratos/future/tests/vtk_output_process_ref_files/binary2D/Main/test.FixedEdgeNodes_conditions_0.vtu b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/binary2D/Main/test.FixedEdgeNodes_conditions_0.vtu old mode 100644 new mode 100755 similarity index 100% rename from kratos/future/tests/vtk_output_process_ref_files/binary2D/Main/test.FixedEdgeNodes_conditions_0.vtu rename to kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/binary2D/Main/test.FixedEdgeNodes_conditions_0.vtu diff --git a/kratos/future/tests/vtk_output_process_ref_files/binary2D/Main/test.MovingNodes_conditions_0.vtu b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/binary2D/Main/test.MovingNodes_conditions_0.vtu old mode 100644 new mode 100755 similarity index 100% rename from kratos/future/tests/vtk_output_process_ref_files/binary2D/Main/test.MovingNodes_conditions_0.vtu rename to kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/binary2D/Main/test.MovingNodes_conditions_0.vtu diff --git a/kratos/future/tests/vtk_output_process_ref_files/binary2D/Main/test_conditions_0.vtu b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/binary2D/Main/test_conditions_0.vtu old mode 100644 new mode 100755 similarity index 100% rename from kratos/future/tests/vtk_output_process_ref_files/binary2D/Main/test_conditions_0.vtu rename to kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/binary2D/Main/test_conditions_0.vtu diff --git a/kratos/future/tests/vtk_output_process_ref_files/binary2D/Main/test_elements_0.vtu b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/binary2D/Main/test_elements_0.vtu old mode 100644 new mode 100755 similarity index 100% rename from kratos/future/tests/vtk_output_process_ref_files/binary2D/Main/test_elements_0.vtu rename to kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/binary2D/Main/test_elements_0.vtu diff --git a/kratos/future/tests/vtk_output_process_ref_files/binary3D/Main.pvd b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/binary3D/Main.pvd old mode 100644 new mode 100755 similarity index 100% rename from kratos/future/tests/vtk_output_process_ref_files/binary3D/Main.pvd rename to kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/binary3D/Main.pvd diff --git a/kratos/future/tests/vtk_output_process_ref_files/binary3D/Main/test_conditions_0.vtu b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/binary3D/Main/test_conditions_0.vtu old mode 100644 new mode 100755 similarity index 100% rename from kratos/future/tests/vtk_output_process_ref_files/binary3D/Main/test_conditions_0.vtu rename to kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/binary3D/Main/test_conditions_0.vtu diff --git a/kratos/future/tests/vtk_output_process_ref_files/binary3D/Main/test_elements_0.vtu b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/binary3D/Main/test_elements_0.vtu old mode 100644 new mode 100755 similarity index 100% rename from kratos/future/tests/vtk_output_process_ref_files/binary3D/Main/test_elements_0.vtu rename to kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/binary3D/Main/test_elements_0.vtu diff --git a/kratos/future/tests/vtk_output_process_ref_files/compressed_raw2D/Main.pvd b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/compressed_raw2D/Main.pvd old mode 100644 new mode 100755 similarity index 100% rename from kratos/future/tests/vtk_output_process_ref_files/compressed_raw2D/Main.pvd rename to kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/compressed_raw2D/Main.pvd diff --git a/kratos/future/tests/vtk_output_process_ref_files/compressed_raw2D/Main/test.FixedEdgeNodes_conditions_0.vtu b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/compressed_raw2D/Main/test.FixedEdgeNodes_conditions_0.vtu old mode 100644 new mode 100755 similarity index 100% rename from kratos/future/tests/vtk_output_process_ref_files/compressed_raw2D/Main/test.FixedEdgeNodes_conditions_0.vtu rename to kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/compressed_raw2D/Main/test.FixedEdgeNodes_conditions_0.vtu diff --git a/kratos/future/tests/vtk_output_process_ref_files/compressed_raw2D/Main/test.MovingNodes_conditions_0.vtu b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/compressed_raw2D/Main/test.MovingNodes_conditions_0.vtu old mode 100644 new mode 100755 similarity index 100% rename from kratos/future/tests/vtk_output_process_ref_files/compressed_raw2D/Main/test.MovingNodes_conditions_0.vtu rename to kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/compressed_raw2D/Main/test.MovingNodes_conditions_0.vtu diff --git a/kratos/future/tests/vtk_output_process_ref_files/compressed_raw2D/Main/test_conditions_0.vtu b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/compressed_raw2D/Main/test_conditions_0.vtu old mode 100644 new mode 100755 similarity index 100% rename from kratos/future/tests/vtk_output_process_ref_files/compressed_raw2D/Main/test_conditions_0.vtu rename to kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/compressed_raw2D/Main/test_conditions_0.vtu diff --git a/kratos/future/tests/vtk_output_process_ref_files/compressed_raw2D/Main/test_elements_0.vtu b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/compressed_raw2D/Main/test_elements_0.vtu old mode 100644 new mode 100755 similarity index 100% rename from kratos/future/tests/vtk_output_process_ref_files/compressed_raw2D/Main/test_elements_0.vtu rename to kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/compressed_raw2D/Main/test_elements_0.vtu diff --git a/kratos/future/tests/vtk_output_process_ref_files/compressed_raw3D/Main.pvd b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/compressed_raw3D/Main.pvd old mode 100644 new mode 100755 similarity index 100% rename from kratos/future/tests/vtk_output_process_ref_files/compressed_raw3D/Main.pvd rename to kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/compressed_raw3D/Main.pvd diff --git a/kratos/future/tests/vtk_output_process_ref_files/compressed_raw3D/Main/test_conditions_0.vtu b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/compressed_raw3D/Main/test_conditions_0.vtu old mode 100644 new mode 100755 similarity index 100% rename from kratos/future/tests/vtk_output_process_ref_files/compressed_raw3D/Main/test_conditions_0.vtu rename to kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/compressed_raw3D/Main/test_conditions_0.vtu diff --git a/kratos/future/tests/vtk_output_process_ref_files/compressed_raw3D/Main/test_elements_0.vtu b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/compressed_raw3D/Main/test_elements_0.vtu old mode 100644 new mode 100755 similarity index 100% rename from kratos/future/tests/vtk_output_process_ref_files/compressed_raw3D/Main/test_elements_0.vtu rename to kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/compressed_raw3D/Main/test_elements_0.vtu diff --git a/kratos/future/tests/vtk_output_process_ref_files/raw2D/Main.pvd b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/raw2D/Main.pvd old mode 100644 new mode 100755 similarity index 100% rename from kratos/future/tests/vtk_output_process_ref_files/raw2D/Main.pvd rename to kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/raw2D/Main.pvd diff --git a/kratos/future/tests/vtk_output_process_ref_files/raw2D/Main/test.FixedEdgeNodes_conditions_0.vtu b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/raw2D/Main/test.FixedEdgeNodes_conditions_0.vtu old mode 100644 new mode 100755 similarity index 100% rename from kratos/future/tests/vtk_output_process_ref_files/raw2D/Main/test.FixedEdgeNodes_conditions_0.vtu rename to kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/raw2D/Main/test.FixedEdgeNodes_conditions_0.vtu diff --git a/kratos/future/tests/vtk_output_process_ref_files/raw2D/Main/test.MovingNodes_conditions_0.vtu b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/raw2D/Main/test.MovingNodes_conditions_0.vtu old mode 100644 new mode 100755 similarity index 100% rename from kratos/future/tests/vtk_output_process_ref_files/raw2D/Main/test.MovingNodes_conditions_0.vtu rename to kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/raw2D/Main/test.MovingNodes_conditions_0.vtu diff --git a/kratos/future/tests/vtk_output_process_ref_files/raw2D/Main/test_conditions_0.vtu b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/raw2D/Main/test_conditions_0.vtu old mode 100644 new mode 100755 similarity index 100% rename from kratos/future/tests/vtk_output_process_ref_files/raw2D/Main/test_conditions_0.vtu rename to kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/raw2D/Main/test_conditions_0.vtu diff --git a/kratos/future/tests/vtk_output_process_ref_files/raw2D/Main/test_elements_0.vtu b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/raw2D/Main/test_elements_0.vtu old mode 100644 new mode 100755 similarity index 100% rename from kratos/future/tests/vtk_output_process_ref_files/raw2D/Main/test_elements_0.vtu rename to kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/raw2D/Main/test_elements_0.vtu diff --git a/kratos/future/tests/vtk_output_process_ref_files/raw3D/Main.pvd b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/raw3D/Main.pvd old mode 100644 new mode 100755 similarity index 100% rename from kratos/future/tests/vtk_output_process_ref_files/raw3D/Main.pvd rename to kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/raw3D/Main.pvd diff --git a/kratos/future/tests/vtk_output_process_ref_files/raw3D/Main/test_conditions_0.vtu b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/raw3D/Main/test_conditions_0.vtu old mode 100644 new mode 100755 similarity index 100% rename from kratos/future/tests/vtk_output_process_ref_files/raw3D/Main/test_conditions_0.vtu rename to kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/raw3D/Main/test_conditions_0.vtu diff --git a/kratos/future/tests/vtk_output_process_ref_files/raw3D/Main/test_elements_0.vtu b/kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/raw3D/Main/test_elements_0.vtu old mode 100644 new mode 100755 similarity index 100% rename from kratos/future/tests/vtk_output_process_ref_files/raw3D/Main/test_elements_0.vtu rename to kratos/tests/auxiliar_files_for_python_unittest/vtk_output_process_ref_files/raw3D/Main/test_elements_0.vtu From b224d0768c0681262e705e1a248a1dc52c4b61a6 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 20 Feb 2026 08:37:44 +0100 Subject: [PATCH 108/116] update vtu output tests --- kratos/tests/test_vtu_output.py | 34 +++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/kratos/tests/test_vtu_output.py b/kratos/tests/test_vtu_output.py index 1b34d6009f6b..13a0c7015ab7 100755 --- a/kratos/tests/test_vtu_output.py +++ b/kratos/tests/test_vtu_output.py @@ -79,25 +79,37 @@ def test_WriteMeshCompressedRaw(self): self.WriteVtu(Kratos.VtuOutput.COMPRESSED_RAW) def test_WriteMeshAsciiWithError(self): - self.addCleanup(kratos_utils.DeleteDirectoryIfExisting, "auxiliar_files_for_python_unittest/vtk_output_process_ref_files/temp") with self.assertRaises(RuntimeError): self.WriteVtu(Kratos.VtuOutput.ASCII, True) + with kratos_unittest.WorkFolderScope("auxiliar_files_for_python_unittest/vtk_output_process_ref_files", __file__, True): + kratos_utils.DeleteFileIfExisting("temp/ascii2D/Main/test_elements_0.vtu") + kratos_utils.DeleteFileIfExisting("temp/ascii3D/Main/test_elements_0.vtu") + def test_WriteMeshBinaryWithError(self): - self.addCleanup(kratos_utils.DeleteDirectoryIfExisting, "auxiliar_files_for_python_unittest/vtk_output_process_ref_files/temp") with self.assertRaises(RuntimeError): self.WriteVtu(Kratos.VtuOutput.BINARY, True) + with kratos_unittest.WorkFolderScope("auxiliar_files_for_python_unittest/vtk_output_process_ref_files", __file__, True): + kratos_utils.DeleteFileIfExisting("temp/binary2D/Main/test_elements_0.vtu") + kratos_utils.DeleteFileIfExisting("temp/binary3D/Main/test_elements_0.vtu") + def test_WriteMeshRawWithError(self): - self.addCleanup(kratos_utils.DeleteDirectoryIfExisting, "auxiliar_files_for_python_unittest/vtk_output_process_ref_files/temp") with self.assertRaises(RuntimeError): self.WriteVtu(Kratos.VtuOutput.RAW, True) + with kratos_unittest.WorkFolderScope("auxiliar_files_for_python_unittest/vtk_output_process_ref_files", __file__, True): + kratos_utils.DeleteFileIfExisting("temp/raw2D/Main/test_elements_0.vtu") + kratos_utils.DeleteFileIfExisting("temp/raw3D/Main/test_elements_0.vtu") + def test_WriteMeshCompressedRawWithError(self): - self.addCleanup(kratos_utils.DeleteDirectoryIfExisting, "auxiliar_files_for_python_unittest/vtk_output_process_ref_files/temp") with self.assertRaises(RuntimeError): self.WriteVtu(Kratos.VtuOutput.COMPRESSED_RAW, True) + with kratos_unittest.WorkFolderScope("auxiliar_files_for_python_unittest/vtk_output_process_ref_files", __file__, True): + kratos_utils.DeleteFileIfExisting("temp/compressed_raw2D/Main/test_elements_0.vtu") + kratos_utils.DeleteFileIfExisting("temp/compressed_raw3D/Main/test_elements_0.vtu") + def Check(self, output_prefix, reference_prefix): def check_file(output_file_name: str, reference_file_name: str): ## Settings string in json format @@ -115,13 +127,15 @@ def check_file(output_file_name: str, reference_file_name: str): check_file(f"{output_prefix}/{file_path.name}", str(file_path)) check_file(f"{output_prefix}.pvd", f"{reference_prefix}.pvd") - kratos_utils.DeleteDirectoryIfExistingAndEmpty("temp") - class TestVtuOutput2D(TestVtuOutputBase, kratos_unittest.TestCase): @classmethod def setUpClass(cls) -> None: super().setUpClass("2D", SetupModelPart2D, output_sub_model_parts = True) + def tearDown(self): + with kratos_unittest.WorkFolderScope("auxiliar_files_for_python_unittest/vtk_output_process_ref_files", __file__, True): + kratos_utils.DeleteDirectoryIfExistingAndEmpty("temp") + class TestVtuOutput3D(TestVtuOutputBase, kratos_unittest.TestCase): @classmethod def setUpClass(cls) -> None: @@ -130,6 +144,10 @@ def setUpClass(cls) -> None: # some random nodes. Hence sub_model_part output is disabled. super().setUpClass("3D", SetupModelPart3D, output_sub_model_parts = False) + def tearDown(self): + with kratos_unittest.WorkFolderScope("auxiliar_files_for_python_unittest/vtk_output_process_ref_files", __file__, True): + kratos_utils.DeleteDirectoryIfExistingAndEmpty("temp") + class TestVtuOutput(kratos_unittest.TestCase): @classmethod def setUpClass(cls): @@ -573,8 +591,8 @@ def __GetUnstructuredGridList(unstructured_grid_list: 'list[tuple[Kratos.ModelPa @classmethod def tearDownClass(cls): - kratos_utils.DeleteDirectoryIfExistingAndEmpty("temp") - + with kratos_unittest.WorkFolderScope("auxiliar_files_for_python_unittest/vtk_output_process_ref_files", __file__, True): + kratos_utils.DeleteDirectoryIfExistingAndEmpty("temp") if __name__ == "__main__": Kratos.Logger.GetDefaultOutput().SetSeverity(Kratos.Logger.Severity.INFO) From 713954ae3895da46ea111f5393e92176db99fd8f Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 20 Feb 2026 08:58:55 +0100 Subject: [PATCH 109/116] update opt_prob_vtu_output --- .../optimization_problem_vtu_output_process.py | 17 +++++++---------- ...t_optimization_problem_vtu_output_process.py | 1 - 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/applications/OptimizationApplication/python_scripts/processes/optimization_problem_vtu_output_process.py b/applications/OptimizationApplication/python_scripts/processes/optimization_problem_vtu_output_process.py index af836c71ce35..957e28ce6c41 100644 --- a/applications/OptimizationApplication/python_scripts/processes/optimization_problem_vtu_output_process.py +++ b/applications/OptimizationApplication/python_scripts/processes/optimization_problem_vtu_output_process.py @@ -75,7 +75,7 @@ def __init__(self, parameters: 'dict[str, Any]', model_part: Kratos.ModelPart, o else: self.output_path = Path(".") - self.vtu_output: Kratos.Future.VtuOutput = Kratos.Future.VtuOutput(model_part, parameters["configuration"], parameters["writer_format"], parameters["precision"], output_sub_model_parts=True, echo_level=parameters["echo_level"], write_ids=parameters["write_ids"]) + self.vtu_output: Kratos.VtuOutput = Kratos.VtuOutput(model_part, parameters["is_initial_configuration"], parameters["writer_format"], parameters["precision"], output_sub_model_parts=True, echo_level=parameters["echo_level"], write_ids=parameters["write_ids"]) self.list_of_tensor_adaptor_data: 'list[TensorAdaptorData]' = [] def AddTensorAdaptorData(self, tensor_adaptor_data: TensorAdaptorData) -> bool: @@ -128,20 +128,17 @@ def __init__(self, model: Kratos.Model, parameters: Kratos.Parameters, optimizat self.write_ids = parameters["write_ids"].GetBool() file_format = parameters["file_format"].GetString() if file_format == "ascii": - self.writer_format = Kratos.Future.VtuOutput.ASCII + self.writer_format = Kratos.VtuOutput.ASCII elif file_format == "binary": - self.writer_format = Kratos.Future.VtuOutput.BINARY + self.writer_format = Kratos.VtuOutput.BINARY elif file_format == "raw": - self.writer_format = Kratos.Future.VtuOutput.RAW + self.writer_format = Kratos.VtuOutput.RAW elif file_format == "compressed_raw": - self.writer_format = Kratos.Future.VtuOutput.COMPRESSED_RAW + self.writer_format = Kratos.VtuOutput.COMPRESSED_RAW else: raise RuntimeError(f"Only supports \"ascii\", \"binary\", \"raw\", and \"compressed_raw\" file_format. [ provided file_format = \"{file_format}\" ].") - if parameters["write_deformed_configuration"].GetBool(): - self.configuration = Kratos.Configuration.Current - else: - self.configuration = Kratos.Configuration.Initial + self.is_initial_configuration = not parameters["write_deformed_configuration"].GetBool() self.list_of_component_names = parameters["list_of_output_components"].GetStringArray() self.list_of_tensor_adaptor_vtu_outputs: 'list[TensorAdaptorVtuOutput]' = [] @@ -194,7 +191,7 @@ def _AddContainerTensorAdaptor(self, tensor_adaptor_data: TensorAdaptorData): if not found_vtu_output: vtu_parameters = { "output_file_name_prefix": self.file_name, - "configuration": self.configuration, + "is_initial_configuration": self.is_initial_configuration, "writer_format": self.writer_format, "precision": self.output_precision, "save_output_files_in_folder": self.save_output_files_in_folder, diff --git a/applications/OptimizationApplication/tests/process_tests/test_optimization_problem_vtu_output_process.py b/applications/OptimizationApplication/tests/process_tests/test_optimization_problem_vtu_output_process.py index f0b46c94e48c..9df77433413a 100644 --- a/applications/OptimizationApplication/tests/process_tests/test_optimization_problem_vtu_output_process.py +++ b/applications/OptimizationApplication/tests/process_tests/test_optimization_problem_vtu_output_process.py @@ -15,7 +15,6 @@ from KratosMultiphysics.compare_two_files_check_process import CompareTwoFilesCheckProcess -@kratos_unittest.skipUnless(hasattr(Kratos, "Future"), "Kratos is not compiled with KRATOS_FUTURE = ON.") class TestOptimizationProblemVtuOutputProcess(kratos_unittest.TestCase): class DummyResponseFunction(ResponseFunction): def __init__(self, response_name: str, model_part: Kratos.ModelPart) -> None: From 5acea56904a52a66c2428e40116c2ead378c710d Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Fri, 20 Feb 2026 12:25:44 +0100 Subject: [PATCH 110/116] fix explicit filter outputs --- .../explicit_filter_reference_constant.vtu | 13 +++++++------ .../filtering/explicit_filter_reference_cosine.vtu | 13 +++++++------ .../explicit_filter_reference_gaussian.vtu | 13 +++++++------ .../filtering/explicit_filter_reference_linear.vtu | 13 +++++++------ .../filtering/explicit_filter_reference_quartic.vtu | 13 +++++++------ .../explicit_filter_reference_sigmoidal.vtu | 13 +++++++------ ...plicit_filter_reference_sigmoidal_cloud_mesh.vtu | 13 +++++++------ .../tests/filtering/explicit_filters_tests.py | 7 +++++-- 8 files changed, 54 insertions(+), 44 deletions(-) diff --git a/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_constant.vtu b/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_constant.vtu index a86b2420840e..79fa9ef1662b 100644 --- a/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_constant.vtu +++ b/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_constant.vtu @@ -1,19 +1,20 @@ - + + - + - + -5.000000e-01 -5.000000e-01 0.000000e+00 -2.954690e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 -3.076218e-01 6.730670e-02 -2.698146e-01 -3.684091e-01 3.682268e-02 -3.210687e-01 -2.152692e-01 1.696515e-01 -8.165576e-02 -5.000000e-01 0.000000e+00 -5.000000e-01 -1.201263e-01 2.427572e-01 -1.393353e-01 -2.057058e-01 1.764073e-01 -2.991886e-02 -3.652212e-01 4.020307e-02 -2.923024e-01 -6.213435e-02 2.469612e-01 1.230270e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 8.486384e-02 2.546585e-01 7.102194e-02 -1.981571e-01 1.665123e-01 -3.725551e-02 -3.157286e-02 2.356577e-01 1.753316e-01 -3.578146e-01 3.830592e-02 -1.995909e-01 1.408093e-01 2.447731e-01 -5.000000e-01 2.542415e-01 2.301170e-01 -3.392484e-01 2.635720e-01 2.484821e-01 3.289313e-01 -5.000000e-01 0.000000e+00 1.686987e-01 -2.344447e-02 1.899916e-01 2.752834e-01 -1.876647e-01 1.105251e-01 4.651544e-02 1.553755e-01 2.299026e-01 -1.946200e-01 3.014690e-01 2.421528e-01 3.789940e-01 -3.494305e-01 3.224430e-02 -7.595017e-02 2.822785e-01 2.385466e-01 -5.000000e-01 3.894072e-01 2.360903e-01 -3.974708e-01 4.025171e-01 2.427420e-01 -2.400169e-01 4.028732e-01 2.438698e-01 3.160794e-02 3.053247e-01 2.304882e-01 3.629834e-01 -1.880867e-02 6.147739e-02 -1.319979e-01 4.029774e-01 2.357441e-01 2.863519e-01 1.357811e-01 1.110552e-01 1.332429e-01 2.834209e-01 1.937152e-01 5.281389e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 5.000000e-01 2.152277e-01 -3.988510e-01 5.000000e-01 2.008792e-01 -2.211396e-02 4.033233e-01 2.138188e-01 -2.937882e-01 5.000000e-01 2.101694e-01 5.357141e-01 -3.036836e-01 0.000000e+00 -1.873007e-01 5.000000e-01 1.956806e-01 7.894423e-02 4.033102e-01 2.088962e-01 2.533139e-01 2.989023e-01 1.271129e-01 -8.245013e-02 5.000000e-01 1.928728e-01 5.387344e-01 -1.085301e-01 0.000000e+00 1.823984e-01 4.033293e-01 1.680583e-01 2.526017e-02 5.000000e-01 1.922700e-01 3.801274e-01 2.670541e-01 3.722506e-02 1.270189e-01 5.000000e-01 1.712776e-01 5.382499e-01 9.470425e-02 0.000000e+00 2.828839e-01 4.037465e-01 7.916664e-02 2.266649e-01 5.000000e-01 9.571167e-02 5.364034e-01 2.580094e-01 0.000000e+00 4.331546e-01 4.032447e-01 1.492143e-02 3.292619e-01 5.000000e-01 4.987022e-02 5.324171e-01 3.904917e-01 0.000000e+00 4.279950e-01 5.000000e-01 1.038714e-02 5.300883e-01 5.000000e-01 0.000000e+00 - + 56 55 52 47 45 40 37 35 26 53 50 49 42 39 30 55 53 52 45 42 36 26 34 25 50 47 44 39 37 27 40 45 36 40 36 28 49 50 44 49 44 41 52 53 49 52 49 46 44 47 40 44 40 32 26 35 34 30 39 27 30 27 22 36 42 30 36 30 24 27 37 26 27 26 17 56 52 54 28 36 24 28 24 21 46 49 41 46 41 31 22 27 17 22 17 15 17 26 16 41 44 32 41 32 31 32 40 28 32 28 21 24 30 22 24 22 15 52 46 51 51 54 52 25 16 26 21 24 15 15 17 11 46 31 48 48 51 46 16 11 17 43 48 29 11 6 9 29 48 31 29 31 19 19 31 21 29 19 20 20 19 12 29 20 43 12 19 13 20 12 14 13 19 21 13 21 15 12 13 7 14 12 8 20 14 23 9 6 4 7 13 9 8 12 7 23 14 18 23 18 33 11 9 15 15 9 13 14 8 10 14 10 18 20 23 43 4 6 2 9 4 7 7 4 3 3 4 2 7 3 8 8 3 5 8 5 10 5 3 1 0 3 2 0 1 3 33 38 23 23 38 43 31 32 21 - + 3 6 9 12 15 18 21 24 27 30 33 36 39 42 45 48 51 54 57 60 63 66 69 72 75 78 81 84 87 90 93 96 99 102 105 108 111 114 117 120 123 126 129 132 135 138 141 144 147 150 153 156 159 162 165 168 171 174 177 180 183 186 189 192 195 198 201 204 207 210 213 216 219 222 225 228 231 234 237 240 243 246 249 252 255 - + 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 diff --git a/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_cosine.vtu b/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_cosine.vtu index 83716bed3169..35842a636f95 100644 --- a/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_cosine.vtu +++ b/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_cosine.vtu @@ -1,19 +1,20 @@ - + + - + - + -5.000000e-01 -5.000000e-01 0.000000e+00 -2.991491e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 -3.100072e-01 4.989820e-02 -2.748267e-01 -3.702636e-01 2.693719e-02 -3.245682e-01 -2.254517e-01 1.489256e-01 -9.196332e-02 -5.000000e-01 0.000000e+00 -5.000000e-01 -1.280630e-01 2.070997e-01 -1.450095e-01 -2.189538e-01 1.749638e-01 -3.659211e-02 -3.673344e-01 3.140215e-02 -2.954990e-01 -7.607154e-02 2.981890e-01 1.182097e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 8.582400e-02 2.638892e-01 7.642142e-02 -2.072924e-01 1.605990e-01 -3.029159e-02 -4.244769e-02 3.105166e-01 1.752558e-01 -3.587013e-01 2.914530e-02 -2.034831e-01 1.411768e-01 3.098708e-01 -5.000000e-01 2.584408e-01 2.268754e-01 -3.414377e-01 2.681899e-01 2.538098e-01 3.217517e-01 -5.000000e-01 0.000000e+00 1.881924e-01 -2.704537e-02 2.105209e-01 2.847983e-01 -1.909550e-01 9.555792e-02 5.526918e-02 1.585090e-01 2.659499e-01 -2.004494e-01 3.050502e-01 2.462800e-01 3.777562e-01 -3.496018e-01 2.333182e-02 -7.851439e-02 2.866093e-01 2.448954e-01 -5.000000e-01 3.910091e-01 1.775422e-01 -3.986135e-01 4.038014e-01 1.891308e-01 -2.450655e-01 4.045503e-01 1.991841e-01 3.197844e-02 3.088370e-01 2.109643e-01 3.780917e-01 -1.709096e-02 5.252044e-02 -1.382457e-01 4.045633e-01 1.948586e-01 3.012772e-01 1.413521e-01 8.940033e-02 1.376671e-01 2.873000e-01 1.737178e-01 5.190268e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 5.000000e-01 1.375057e-01 -3.996857e-01 5.000000e-01 1.516662e-01 -3.014878e-02 4.045626e-01 1.797287e-01 -2.981346e-01 5.000000e-01 1.575114e-01 5.305128e-01 -3.026884e-01 0.000000e+00 -1.940829e-01 5.000000e-01 1.568791e-01 7.628034e-02 4.045778e-01 1.523165e-01 2.585399e-01 3.025401e-01 8.752896e-02 -8.793837e-02 5.000000e-01 1.464772e-01 5.424553e-01 -1.051667e-01 0.000000e+00 1.804156e-01 4.045889e-01 1.034956e-01 1.770496e-02 5.000000e-01 1.274626e-01 3.844219e-01 2.704743e-01 2.568950e-02 1.220064e-01 5.000000e-01 9.875492e-02 5.442603e-01 9.954487e-02 0.000000e+00 2.818124e-01 4.045666e-01 5.408987e-02 2.244435e-01 5.000000e-01 6.085503e-02 5.366422e-01 2.609213e-01 0.000000e+00 4.292998e-01 4.038212e-01 7.655538e-03 3.248422e-01 5.000000e-01 2.617334e-02 5.283949e-01 3.910444e-01 0.000000e+00 4.238597e-01 5.000000e-01 5.957351e-03 5.212440e-01 5.000000e-01 0.000000e+00 - + 56 55 52 47 45 40 37 35 26 53 50 49 42 39 30 55 53 52 45 42 36 26 34 25 50 47 44 39 37 27 40 45 36 40 36 28 49 50 44 49 44 41 52 53 49 52 49 46 44 47 40 44 40 32 26 35 34 30 39 27 30 27 22 36 42 30 36 30 24 27 37 26 27 26 17 56 52 54 28 36 24 28 24 21 46 49 41 46 41 31 22 27 17 22 17 15 17 26 16 41 44 32 41 32 31 32 40 28 32 28 21 24 30 22 24 22 15 52 46 51 51 54 52 25 16 26 21 24 15 15 17 11 46 31 48 48 51 46 16 11 17 43 48 29 11 6 9 29 48 31 29 31 19 19 31 21 29 19 20 20 19 12 29 20 43 12 19 13 20 12 14 13 19 21 13 21 15 12 13 7 14 12 8 20 14 23 9 6 4 7 13 9 8 12 7 23 14 18 23 18 33 11 9 15 15 9 13 14 8 10 14 10 18 20 23 43 4 6 2 9 4 7 7 4 3 3 4 2 7 3 8 8 3 5 8 5 10 5 3 1 0 3 2 0 1 3 33 38 23 23 38 43 31 32 21 - + 3 6 9 12 15 18 21 24 27 30 33 36 39 42 45 48 51 54 57 60 63 66 69 72 75 78 81 84 87 90 93 96 99 102 105 108 111 114 117 120 123 126 129 132 135 138 141 144 147 150 153 156 159 162 165 168 171 174 177 180 183 186 189 192 195 198 201 204 207 210 213 216 219 222 225 228 231 234 237 240 243 246 249 252 255 - + 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 diff --git a/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_gaussian.vtu b/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_gaussian.vtu index acd7ad179240..36b5ef0d6d0b 100644 --- a/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_gaussian.vtu +++ b/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_gaussian.vtu @@ -1,19 +1,20 @@ - + + - + - + -5.000000e-01 -5.000000e-01 0.000000e+00 -3.007196e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 -3.065034e-01 2.461872e-02 -2.788266e-01 -3.689216e-01 1.477026e-02 -3.298575e-01 -2.442489e-01 1.116619e-01 -9.965241e-02 -5.000000e-01 0.000000e+00 -5.000000e-01 -1.489714e-01 1.421952e-01 -1.600906e-01 -2.630415e-01 1.498938e-01 -5.029431e-02 -3.658966e-01 1.499640e-02 -3.247315e-01 -1.807785e-01 4.150662e-01 1.036977e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 1.166647e-01 2.882023e-01 8.467524e-02 -2.516502e-01 1.692512e-01 6.828922e-03 -1.266132e-01 4.580222e-01 1.619512e-01 -3.583053e-01 1.769232e-02 -2.279133e-01 2.380321e-01 4.755744e-01 -5.000000e-01 2.668125e-01 1.566494e-01 -3.445339e-01 2.865280e-01 2.415987e-01 3.082706e-01 -5.000000e-01 0.000000e+00 2.803267e-01 -4.437674e-02 2.656870e-01 3.169091e-01 -2.064629e-01 1.133210e-01 1.261006e-01 2.368107e-01 3.728273e-01 -2.077050e-01 3.145934e-01 1.896257e-01 3.753464e-01 -3.488286e-01 1.742187e-02 -8.583488e-02 2.983067e-01 1.794044e-01 -5.000000e-01 3.916102e-01 1.205986e-01 -3.991628e-01 4.047192e-01 1.628128e-01 -2.484632e-01 4.056065e-01 1.377838e-01 3.023691e-02 3.167875e-01 1.609727e-01 4.056037e-01 -3.865631e-03 3.480217e-02 -1.449796e-01 4.056228e-01 1.213960e-01 3.547500e-01 1.669525e-01 7.360623e-02 1.396955e-01 2.960251e-01 1.419123e-01 5.054796e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 5.000000e-01 8.278275e-02 -4.000050e-01 5.000000e-01 1.129721e-01 -4.006627e-02 4.055402e-01 1.117794e-01 -2.994376e-01 5.000000e-01 1.028399e-01 5.163163e-01 -3.009242e-01 0.000000e+00 -1.978510e-01 5.000000e-01 9.015215e-02 6.645628e-02 4.052832e-01 1.001378e-01 2.581368e-01 3.060237e-01 5.668889e-02 -9.568121e-02 5.000000e-01 8.112439e-02 5.436701e-01 -1.012313e-01 0.000000e+00 1.700746e-01 4.049768e-01 6.912835e-02 7.405549e-03 5.000000e-01 7.448219e-02 3.901223e-01 2.754510e-01 1.539805e-02 1.109649e-01 5.000000e-01 6.066822e-02 5.339067e-01 1.044745e-01 0.000000e+00 2.696705e-01 4.047104e-01 3.218763e-02 2.124861e-01 5.000000e-01 3.583752e-02 5.186325e-01 2.620677e-01 0.000000e+00 4.134807e-01 4.038251e-01 3.069018e-03 3.109666e-01 5.000000e-01 1.302683e-02 5.094036e-01 3.909688e-01 0.000000e+00 4.082488e-01 5.000000e-01 2.035539e-03 5.052721e-01 5.000000e-01 0.000000e+00 - + 56 55 52 47 45 40 37 35 26 53 50 49 42 39 30 55 53 52 45 42 36 26 34 25 50 47 44 39 37 27 40 45 36 40 36 28 49 50 44 49 44 41 52 53 49 52 49 46 44 47 40 44 40 32 26 35 34 30 39 27 30 27 22 36 42 30 36 30 24 27 37 26 27 26 17 56 52 54 28 36 24 28 24 21 46 49 41 46 41 31 22 27 17 22 17 15 17 26 16 41 44 32 41 32 31 32 40 28 32 28 21 24 30 22 24 22 15 52 46 51 51 54 52 25 16 26 21 24 15 15 17 11 46 31 48 48 51 46 16 11 17 43 48 29 11 6 9 29 48 31 29 31 19 19 31 21 29 19 20 20 19 12 29 20 43 12 19 13 20 12 14 13 19 21 13 21 15 12 13 7 14 12 8 20 14 23 9 6 4 7 13 9 8 12 7 23 14 18 23 18 33 11 9 15 15 9 13 14 8 10 14 10 18 20 23 43 4 6 2 9 4 7 7 4 3 3 4 2 7 3 8 8 3 5 8 5 10 5 3 1 0 3 2 0 1 3 33 38 23 23 38 43 31 32 21 - + 3 6 9 12 15 18 21 24 27 30 33 36 39 42 45 48 51 54 57 60 63 66 69 72 75 78 81 84 87 90 93 96 99 102 105 108 111 114 117 120 123 126 129 132 135 138 141 144 147 150 153 156 159 162 165 168 171 174 177 180 183 186 189 192 195 198 201 204 207 210 213 216 219 222 225 228 231 234 237 240 243 246 249 252 255 - + 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 diff --git a/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_linear.vtu b/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_linear.vtu index 2b861cbba03f..d43f7c0ba920 100644 --- a/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_linear.vtu +++ b/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_linear.vtu @@ -1,19 +1,20 @@ - + + - + - + -5.000000e-01 -5.000000e-01 0.000000e+00 -2.984309e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 -3.090632e-01 5.436174e-02 -2.735886e-01 -3.696047e-01 2.910589e-02 -3.235740e-01 -2.208024e-01 1.524587e-01 -9.004908e-02 -5.000000e-01 0.000000e+00 -5.000000e-01 -1.234879e-01 2.117089e-01 -1.434763e-01 -2.131620e-01 1.735417e-01 -3.474472e-02 -3.665349e-01 3.364957e-02 -2.946188e-01 -7.011321e-02 2.808892e-01 1.189132e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 8.611614e-02 2.541727e-01 7.332653e-02 -2.034018e-01 1.608959e-01 -3.334529e-02 -3.762377e-02 2.831589e-01 1.743563e-01 -3.582901e-01 3.103324e-02 -2.032132e-01 1.405015e-01 2.886430e-01 -5.000000e-01 2.568230e-01 2.274291e-01 -3.408521e-01 2.664978e-01 2.487852e-01 3.224208e-01 -5.000000e-01 0.000000e+00 1.795062e-01 -2.522745e-02 2.007827e-01 2.804995e-01 -1.896018e-01 9.840379e-02 5.094643e-02 1.569336e-01 2.532075e-01 -1.998390e-01 3.036144e-01 2.402862e-01 3.772478e-01 -3.494974e-01 2.529894e-02 -7.853827e-02 2.850798e-01 2.369196e-01 -5.000000e-01 3.906297e-01 1.896381e-01 -3.984449e-01 4.034598e-01 1.961450e-01 -2.440077e-01 4.040684e-01 2.045413e-01 3.064587e-02 3.076936e-01 2.110629e-01 3.714932e-01 -1.752072e-02 5.460841e-02 -1.374321e-01 4.041132e-01 1.985617e-01 2.953276e-01 1.396039e-01 9.188527e-02 1.340248e-01 2.860416e-01 1.773893e-01 5.212856e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 5.000000e-01 1.529200e-01 -3.995081e-01 5.000000e-01 1.656706e-01 -2.887148e-02 4.041420e-01 1.876080e-01 -2.973288e-01 5.000000e-01 1.699102e-01 5.303911e-01 -3.027443e-01 0.000000e+00 -1.924497e-01 5.000000e-01 1.696402e-01 7.610231e-02 4.041857e-01 1.671537e-01 2.552363e-01 3.015882e-01 9.319230e-02 -8.691318e-02 5.000000e-01 1.617716e-01 5.406742e-01 -1.056860e-01 0.000000e+00 1.795923e-01 4.042944e-01 1.140288e-01 1.917062e-02 5.000000e-01 1.462019e-01 3.820607e-01 2.695205e-01 2.801299e-02 1.232378e-01 5.000000e-01 1.109758e-01 5.415876e-01 9.798155e-02 0.000000e+00 2.813950e-01 4.043421e-01 5.985903e-02 2.253657e-01 5.000000e-01 7.030418e-02 5.355878e-01 2.602398e-01 0.000000e+00 4.295031e-01 4.037088e-01 8.804585e-03 3.260202e-01 5.000000e-01 3.112911e-02 5.299791e-01 3.909227e-01 0.000000e+00 4.256232e-01 5.000000e-01 7.006080e-03 5.243080e-01 5.000000e-01 0.000000e+00 - + 56 55 52 47 45 40 37 35 26 53 50 49 42 39 30 55 53 52 45 42 36 26 34 25 50 47 44 39 37 27 40 45 36 40 36 28 49 50 44 49 44 41 52 53 49 52 49 46 44 47 40 44 40 32 26 35 34 30 39 27 30 27 22 36 42 30 36 30 24 27 37 26 27 26 17 56 52 54 28 36 24 28 24 21 46 49 41 46 41 31 22 27 17 22 17 15 17 26 16 41 44 32 41 32 31 32 40 28 32 28 21 24 30 22 24 22 15 52 46 51 51 54 52 25 16 26 21 24 15 15 17 11 46 31 48 48 51 46 16 11 17 43 48 29 11 6 9 29 48 31 29 31 19 19 31 21 29 19 20 20 19 12 29 20 43 12 19 13 20 12 14 13 19 21 13 21 15 12 13 7 14 12 8 20 14 23 9 6 4 7 13 9 8 12 7 23 14 18 23 18 33 11 9 15 15 9 13 14 8 10 14 10 18 20 23 43 4 6 2 9 4 7 7 4 3 3 4 2 7 3 8 8 3 5 8 5 10 5 3 1 0 3 2 0 1 3 33 38 23 23 38 43 31 32 21 - + 3 6 9 12 15 18 21 24 27 30 33 36 39 42 45 48 51 54 57 60 63 66 69 72 75 78 81 84 87 90 93 96 99 102 105 108 111 114 117 120 123 126 129 132 135 138 141 144 147 150 153 156 159 162 165 168 171 174 177 180 183 186 189 192 195 198 201 204 207 210 213 216 219 222 225 228 231 234 237 240 243 246 249 252 255 - + 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 diff --git a/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_quartic.vtu b/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_quartic.vtu index 8da26cf239a8..1eef19b848f5 100644 --- a/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_quartic.vtu +++ b/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_quartic.vtu @@ -1,19 +1,20 @@ - + + - + - + -5.000000e-01 -5.000000e-01 0.000000e+00 -3.005306e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 -3.084094e-01 2.904672e-02 -2.781905e-01 -3.702707e-01 1.833036e-02 -3.288798e-01 -2.421803e-01 1.241736e-01 -9.836984e-02 -5.000000e-01 0.000000e+00 -5.000000e-01 -1.429232e-01 1.650544e-01 -1.544300e-01 -2.507383e-01 1.620965e-01 -4.596288e-02 -3.675337e-01 2.014390e-02 -3.092238e-01 -1.458249e-01 3.865500e-01 1.075637e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 1.018206e-01 2.788063e-01 8.602138e-02 -2.347391e-01 1.686538e-01 -5.404185e-03 -9.085495e-02 4.052340e-01 1.690779e-01 -3.591343e-01 2.200021e-02 -2.150380e-01 1.934152e-01 4.413785e-01 -5.000000e-01 2.657863e-01 1.816259e-01 -3.437672e-01 2.829912e-01 2.618104e-01 3.122586e-01 -5.000000e-01 0.000000e+00 2.408036e-01 -3.830894e-02 2.496639e-01 3.070750e-01 -2.011873e-01 1.061233e-01 9.931205e-02 1.965532e-01 3.447156e-01 -2.058705e-01 3.138169e-01 2.185863e-01 3.765714e-01 -3.492675e-01 1.899713e-02 -7.959867e-02 2.976614e-01 2.183210e-01 -5.000000e-01 3.918160e-01 1.355591e-01 -3.990732e-01 4.047109e-01 1.676189e-01 -2.482452e-01 4.057764e-01 1.578931e-01 3.474571e-02 3.155027e-01 1.779249e-01 3.998883e-01 -1.102375e-02 4.102022e-02 -1.431426e-01 4.057045e-01 1.417348e-01 3.405905e-01 1.571028e-01 8.358277e-02 1.450037e-01 2.944865e-01 1.543616e-01 5.092707e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 5.000000e-01 9.948997e-02 -3.999737e-01 5.000000e-01 1.186840e-01 -3.492869e-02 4.056015e-01 1.284975e-01 -2.993998e-01 5.000000e-01 1.157468e-01 5.226269e-01 -3.017300e-01 0.000000e+00 -1.972658e-01 5.000000e-01 1.062603e-01 7.149767e-02 4.054296e-01 1.126431e-01 2.611577e-01 3.057186e-01 6.658259e-02 -9.307051e-02 5.000000e-01 9.522405e-02 5.432768e-01 -1.025692e-01 0.000000e+00 1.746756e-01 4.051303e-01 7.618045e-02 1.156304e-02 5.000000e-01 8.617040e-02 3.885158e-01 2.739824e-01 1.803284e-02 1.146618e-01 5.000000e-01 6.831860e-02 5.409475e-01 1.042419e-01 0.000000e+00 2.752519e-01 4.048810e-01 3.694911e-02 2.159970e-01 5.000000e-01 4.004667e-02 5.274488e-01 2.624167e-01 0.000000e+00 4.196299e-01 4.039275e-01 4.256082e-03 3.153229e-01 5.000000e-01 1.584339e-02 5.163838e-01 3.911172e-01 0.000000e+00 4.132905e-01 5.000000e-01 3.086396e-03 5.099653e-01 5.000000e-01 0.000000e+00 - + 56 55 52 47 45 40 37 35 26 53 50 49 42 39 30 55 53 52 45 42 36 26 34 25 50 47 44 39 37 27 40 45 36 40 36 28 49 50 44 49 44 41 52 53 49 52 49 46 44 47 40 44 40 32 26 35 34 30 39 27 30 27 22 36 42 30 36 30 24 27 37 26 27 26 17 56 52 54 28 36 24 28 24 21 46 49 41 46 41 31 22 27 17 22 17 15 17 26 16 41 44 32 41 32 31 32 40 28 32 28 21 24 30 22 24 22 15 52 46 51 51 54 52 25 16 26 21 24 15 15 17 11 46 31 48 48 51 46 16 11 17 43 48 29 11 6 9 29 48 31 29 31 19 19 31 21 29 19 20 20 19 12 29 20 43 12 19 13 20 12 14 13 19 21 13 21 15 12 13 7 14 12 8 20 14 23 9 6 4 7 13 9 8 12 7 23 14 18 23 18 33 11 9 15 15 9 13 14 8 10 14 10 18 20 23 43 4 6 2 9 4 7 7 4 3 3 4 2 7 3 8 8 3 5 8 5 10 5 3 1 0 3 2 0 1 3 33 38 23 23 38 43 31 32 21 - + 3 6 9 12 15 18 21 24 27 30 33 36 39 42 45 48 51 54 57 60 63 66 69 72 75 78 81 84 87 90 93 96 99 102 105 108 111 114 117 120 123 126 129 132 135 138 141 144 147 150 153 156 159 162 165 168 171 174 177 180 183 186 189 192 195 198 201 204 207 210 213 216 219 222 225 228 231 234 237 240 243 246 249 252 255 - + 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 diff --git a/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_sigmoidal.vtu b/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_sigmoidal.vtu index a86b2420840e..79fa9ef1662b 100644 --- a/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_sigmoidal.vtu +++ b/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_sigmoidal.vtu @@ -1,19 +1,20 @@ - + + - + - + -5.000000e-01 -5.000000e-01 0.000000e+00 -2.954690e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 -3.076218e-01 6.730670e-02 -2.698146e-01 -3.684091e-01 3.682268e-02 -3.210687e-01 -2.152692e-01 1.696515e-01 -8.165576e-02 -5.000000e-01 0.000000e+00 -5.000000e-01 -1.201263e-01 2.427572e-01 -1.393353e-01 -2.057058e-01 1.764073e-01 -2.991886e-02 -3.652212e-01 4.020307e-02 -2.923024e-01 -6.213435e-02 2.469612e-01 1.230270e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 8.486384e-02 2.546585e-01 7.102194e-02 -1.981571e-01 1.665123e-01 -3.725551e-02 -3.157286e-02 2.356577e-01 1.753316e-01 -3.578146e-01 3.830592e-02 -1.995909e-01 1.408093e-01 2.447731e-01 -5.000000e-01 2.542415e-01 2.301170e-01 -3.392484e-01 2.635720e-01 2.484821e-01 3.289313e-01 -5.000000e-01 0.000000e+00 1.686987e-01 -2.344447e-02 1.899916e-01 2.752834e-01 -1.876647e-01 1.105251e-01 4.651544e-02 1.553755e-01 2.299026e-01 -1.946200e-01 3.014690e-01 2.421528e-01 3.789940e-01 -3.494305e-01 3.224430e-02 -7.595017e-02 2.822785e-01 2.385466e-01 -5.000000e-01 3.894072e-01 2.360903e-01 -3.974708e-01 4.025171e-01 2.427420e-01 -2.400169e-01 4.028732e-01 2.438698e-01 3.160794e-02 3.053247e-01 2.304882e-01 3.629834e-01 -1.880867e-02 6.147739e-02 -1.319979e-01 4.029774e-01 2.357441e-01 2.863519e-01 1.357811e-01 1.110552e-01 1.332429e-01 2.834209e-01 1.937152e-01 5.281389e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 5.000000e-01 2.152277e-01 -3.988510e-01 5.000000e-01 2.008792e-01 -2.211396e-02 4.033233e-01 2.138188e-01 -2.937882e-01 5.000000e-01 2.101694e-01 5.357141e-01 -3.036836e-01 0.000000e+00 -1.873007e-01 5.000000e-01 1.956806e-01 7.894423e-02 4.033102e-01 2.088962e-01 2.533139e-01 2.989023e-01 1.271129e-01 -8.245013e-02 5.000000e-01 1.928728e-01 5.387344e-01 -1.085301e-01 0.000000e+00 1.823984e-01 4.033293e-01 1.680583e-01 2.526017e-02 5.000000e-01 1.922700e-01 3.801274e-01 2.670541e-01 3.722506e-02 1.270189e-01 5.000000e-01 1.712776e-01 5.382499e-01 9.470425e-02 0.000000e+00 2.828839e-01 4.037465e-01 7.916664e-02 2.266649e-01 5.000000e-01 9.571167e-02 5.364034e-01 2.580094e-01 0.000000e+00 4.331546e-01 4.032447e-01 1.492143e-02 3.292619e-01 5.000000e-01 4.987022e-02 5.324171e-01 3.904917e-01 0.000000e+00 4.279950e-01 5.000000e-01 1.038714e-02 5.300883e-01 5.000000e-01 0.000000e+00 - + 56 55 52 47 45 40 37 35 26 53 50 49 42 39 30 55 53 52 45 42 36 26 34 25 50 47 44 39 37 27 40 45 36 40 36 28 49 50 44 49 44 41 52 53 49 52 49 46 44 47 40 44 40 32 26 35 34 30 39 27 30 27 22 36 42 30 36 30 24 27 37 26 27 26 17 56 52 54 28 36 24 28 24 21 46 49 41 46 41 31 22 27 17 22 17 15 17 26 16 41 44 32 41 32 31 32 40 28 32 28 21 24 30 22 24 22 15 52 46 51 51 54 52 25 16 26 21 24 15 15 17 11 46 31 48 48 51 46 16 11 17 43 48 29 11 6 9 29 48 31 29 31 19 19 31 21 29 19 20 20 19 12 29 20 43 12 19 13 20 12 14 13 19 21 13 21 15 12 13 7 14 12 8 20 14 23 9 6 4 7 13 9 8 12 7 23 14 18 23 18 33 11 9 15 15 9 13 14 8 10 14 10 18 20 23 43 4 6 2 9 4 7 7 4 3 3 4 2 7 3 8 8 3 5 8 5 10 5 3 1 0 3 2 0 1 3 33 38 23 23 38 43 31 32 21 - + 3 6 9 12 15 18 21 24 27 30 33 36 39 42 45 48 51 54 57 60 63 66 69 72 75 78 81 84 87 90 93 96 99 102 105 108 111 114 117 120 123 126 129 132 135 138 141 144 147 150 153 156 159 162 165 168 171 174 177 180 183 186 189 192 195 198 201 204 207 210 213 216 219 222 225 228 231 234 237 240 243 246 249 252 255 - + 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 diff --git a/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_sigmoidal_cloud_mesh.vtu b/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_sigmoidal_cloud_mesh.vtu index 94d1c9e76e11..adf18909ec28 100644 --- a/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_sigmoidal_cloud_mesh.vtu +++ b/applications/OptimizationApplication/tests/filtering/explicit_filter_reference_sigmoidal_cloud_mesh.vtu @@ -1,19 +1,20 @@ - + + - + - + -5.000000e-01 -5.000000e-01 0.000000e+00 -2.928662e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 -3.196572e-01 9.440912e-02 -2.654477e-01 -3.741035e-01 4.777782e-02 -3.187021e-01 -2.387544e-01 2.155435e-01 -7.001264e-02 -5.000000e-01 0.000000e+00 -5.000000e-01 -1.473493e-01 3.012083e-01 -1.296464e-01 -2.296432e-01 2.291548e-01 -1.636555e-02 -3.710580e-01 5.116060e-02 -2.876728e-01 -8.310409e-02 3.472872e-01 1.411522e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 7.337988e-02 3.385913e-01 9.405021e-02 -2.176542e-01 2.147340e-01 -1.387309e-02 -4.876027e-02 3.427513e-01 1.973531e-01 -3.627544e-01 4.899897e-02 -1.898728e-01 1.345806e-01 3.330873e-01 -5.000000e-01 2.515355e-01 3.270788e-01 -3.359347e-01 2.607184e-01 3.374378e-01 3.540190e-01 -5.000000e-01 0.000000e+00 2.022820e-01 -3.595737e-02 2.655856e-01 3.046035e-01 -2.011431e-01 1.455754e-01 7.198542e-02 1.511903e-01 3.110066e-01 -1.825121e-01 3.004650e-01 3.226735e-01 4.059908e-01 -3.538270e-01 4.439707e-02 -5.823105e-02 2.812785e-01 3.150987e-01 -5.000000e-01 3.891111e-01 3.267258e-01 -3.961261e-01 4.023486e-01 3.307730e-01 -2.304414e-01 4.025753e-01 3.261115e-01 5.498576e-02 3.046761e-01 3.023393e-01 3.991849e-01 -2.817136e-02 8.259695e-02 -1.161994e-01 4.027647e-01 3.141205e-01 3.188636e-01 1.334181e-01 1.420594e-01 1.592942e-01 2.824590e-01 2.610115e-01 5.535213e-01 -5.000000e-01 0.000000e+00 -5.000000e-01 5.000000e-01 3.224182e-01 -3.973126e-01 5.000000e-01 3.209079e-01 -2.104780e-03 4.030529e-01 2.957158e-01 -2.872629e-01 5.000000e-01 3.201875e-01 5.637316e-01 -3.082319e-01 0.000000e+00 -1.724717e-01 5.000000e-01 3.070889e-01 1.034430e-01 4.030980e-01 2.799994e-01 2.825953e-01 2.983075e-01 1.724221e-01 -6.128498e-02 5.000000e-01 2.988654e-01 5.721223e-01 -1.174447e-01 0.000000e+00 2.099742e-01 4.032024e-01 2.264272e-01 5.068848e-02 5.000000e-01 2.867736e-01 4.139670e-01 2.658418e-01 5.427942e-02 1.560699e-01 5.000000e-01 2.487219e-01 5.739391e-01 9.085196e-02 0.000000e+00 3.150009e-01 4.034570e-01 1.325200e-01 2.590307e-01 5.000000e-01 1.760165e-01 5.726293e-01 2.573698e-01 0.000000e+00 4.681638e-01 4.031980e-01 2.200160e-02 3.647395e-01 5.000000e-01 8.505322e-02 5.707811e-01 3.903147e-01 0.000000e+00 4.672538e-01 5.000000e-01 1.991320e-02 5.686700e-01 5.000000e-01 0.000000e+00 - + 56 55 52 47 45 40 37 35 26 53 50 49 42 39 30 55 53 52 45 42 36 26 34 25 50 47 44 39 37 27 40 45 36 40 36 28 49 50 44 49 44 41 52 53 49 52 49 46 44 47 40 44 40 32 26 35 34 30 39 27 30 27 22 36 42 30 36 30 24 27 37 26 27 26 17 56 52 54 28 36 24 28 24 21 46 49 41 46 41 31 22 27 17 22 17 15 17 26 16 41 44 32 41 32 31 32 40 28 32 28 21 24 30 22 24 22 15 52 46 51 51 54 52 25 16 26 21 24 15 15 17 11 46 31 48 48 51 46 16 11 17 43 48 29 11 6 9 29 48 31 29 31 19 19 31 21 29 19 20 20 19 12 29 20 43 12 19 13 20 12 14 13 19 21 13 21 15 12 13 7 14 12 8 20 14 23 9 6 4 7 13 9 8 12 7 23 14 18 23 18 33 11 9 15 15 9 13 14 8 10 14 10 18 20 23 43 4 6 2 9 4 7 7 4 3 3 4 2 7 3 8 8 3 5 8 5 10 5 3 1 0 3 2 0 1 3 33 38 23 23 38 43 31 32 21 - + 3 6 9 12 15 18 21 24 27 30 33 36 39 42 45 48 51 54 57 60 63 66 69 72 75 78 81 84 87 90 93 96 99 102 105 108 111 114 117 120 123 126 129 132 135 138 141 144 147 150 153 156 159 162 165 168 171 174 177 180 183 186 189 192 195 198 201 204 207 210 213 216 219 222 225 228 231 234 237 240 243 246 249 252 255 - + 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 diff --git a/applications/OptimizationApplication/tests/filtering/explicit_filters_tests.py b/applications/OptimizationApplication/tests/filtering/explicit_filters_tests.py index c55459f45fb9..063e0d3fc864 100644 --- a/applications/OptimizationApplication/tests/filtering/explicit_filters_tests.py +++ b/applications/OptimizationApplication/tests/filtering/explicit_filters_tests.py @@ -4,6 +4,7 @@ import KratosMultiphysics as Kratos import KratosMultiphysics.StructuralMechanicsApplication import KratosMultiphysics.OptimizationApplication as KratosOA +from KratosMultiphysics.kratos_utilities import DeleteDirectoryIfExisting, DeleteFileIfExisting from KratosMultiphysics.testing.utilities import ReadModelPart from KratosMultiphysics.compare_two_files_check_process import CompareTwoFilesCheckProcess from KratosMultiphysics.OptimizationApplication.filtering.filter import Factory as FilterFactory @@ -180,7 +181,7 @@ def setUpClass(cls) -> None: cls.filter_data = ComponentDataView("test", cls.optimization_problem) cls.filter_data.SetDataBuffer(1) - cls.vtu_output = Kratos.VtuOutput(cls.model_part, binary_output=Kratos.VtuOutput.ASCII, precision=6) + cls.vtu_output = Kratos.VtuOutput(cls.model_part, output_format=Kratos.VtuOutput.ASCII, precision=6) def setUp(self) -> None: Kratos.TensorAdaptors.NodePositionTensorAdaptor(self.initial_nodal_pos, Kratos.Configuration.Initial, copy=False).StoreData() @@ -284,8 +285,10 @@ def __RunTestCase(self, filter_function_type: str, damping_function_type: str, r "comparison_type" : "deterministic" }""") params["reference_file_name"].SetString(ref_file) - params["output_file_name"].SetString(f"output_{ref_file}") + params["output_file_name"].SetString(f"output_{ref_file[:-4]}/test_elements_0.vtu") CompareTwoFilesCheckProcess(params).Execute() + DeleteDirectoryIfExisting(f"output_{ref_file[:-4]}") + DeleteFileIfExisting(f"output_{ref_file[:-4]}.pvd") if __name__ == "__main__": From d9090ef87bfe1e3598698817afa9a934c4e3bf2a Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Sat, 21 Feb 2026 08:47:26 +0100 Subject: [PATCH 111/116] minor --- .../custom_python/add_custom_control_utilities_to_python.cpp | 1 + .../custom_python/add_custom_tensor_adaptors_to_python.cpp | 3 +-- .../custom_python/add_custom_tensor_adaptors_to_python.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/applications/OptimizationApplication/custom_python/add_custom_control_utilities_to_python.cpp b/applications/OptimizationApplication/custom_python/add_custom_control_utilities_to_python.cpp index 1ed9e339226a..d51ca3fef60d 100644 --- a/applications/OptimizationApplication/custom_python/add_custom_control_utilities_to_python.cpp +++ b/applications/OptimizationApplication/custom_python/add_custom_control_utilities_to_python.cpp @@ -8,6 +8,7 @@ // license: OptimizationApplication/license.txt // // Main author: Reza Najian Asl +// Suneth Warnakulasuriya // // System includes diff --git a/applications/OptimizationApplication/custom_python/add_custom_tensor_adaptors_to_python.cpp b/applications/OptimizationApplication/custom_python/add_custom_tensor_adaptors_to_python.cpp index d200d1edb74e..b9c4d8e994e7 100644 --- a/applications/OptimizationApplication/custom_python/add_custom_tensor_adaptors_to_python.cpp +++ b/applications/OptimizationApplication/custom_python/add_custom_tensor_adaptors_to_python.cpp @@ -7,8 +7,7 @@ // License: BSD License // license: OptimizationApplication/license.txt // -// Main author: Reza Najian Asl, -// Suneth Warnakulasuriya +// Main author: Suneth Warnakulasuriya // // System includes diff --git a/applications/OptimizationApplication/custom_python/add_custom_tensor_adaptors_to_python.h b/applications/OptimizationApplication/custom_python/add_custom_tensor_adaptors_to_python.h index ca3080b9dcfc..44b8b02c4e83 100644 --- a/applications/OptimizationApplication/custom_python/add_custom_tensor_adaptors_to_python.h +++ b/applications/OptimizationApplication/custom_python/add_custom_tensor_adaptors_to_python.h @@ -7,7 +7,7 @@ // License: BSD License // license: OptimizationApplication/license.txt // -// Main author: Reza Najian Asl +// Main author: Suneth Warnakulasuriya // #pragma once From 325b8709a2e5bc0918c90c556cb034dd03d751c2 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Mon, 23 Feb 2026 09:47:02 +0100 Subject: [PATCH 112/116] minor --- .../controls/thickness/shell_thickness_control.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/OptimizationApplication/python_scripts/controls/thickness/shell_thickness_control.py b/applications/OptimizationApplication/python_scripts/controls/thickness/shell_thickness_control.py index d3ef0ed65ef3..4673a463daf2 100644 --- a/applications/OptimizationApplication/python_scripts/controls/thickness/shell_thickness_control.py +++ b/applications/OptimizationApplication/python_scripts/controls/thickness/shell_thickness_control.py @@ -106,7 +106,7 @@ def GetEmptyField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: field.data[:] = 0.0 return field - def GetControlField(self) -> ContainerExpressionTypes: + def GetControlField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: return self.control_phi_field.Clone() def GetPhysicalField(self) -> Kratos.TensorAdaptors.DoubleTensorAdaptor: From 5b32d643951d85a56a1b50ca554338f933c55cc7 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Tue, 24 Feb 2026 21:49:01 +0100 Subject: [PATCH 113/116] fix crlf prob with win and unix --- .../xml_utilities/xml_appended_data_element_wrapper.cpp | 2 +- .../utilities/xml_utilities/xml_ascii_nd_data_element.cpp | 2 +- .../xml_utilities/xml_base64_binary_nd_data_element.cpp | 2 +- kratos/utilities/xml_utilities/xml_element.cpp | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/kratos/utilities/xml_utilities/xml_appended_data_element_wrapper.cpp b/kratos/utilities/xml_utilities/xml_appended_data_element_wrapper.cpp index cf731a4362b3..b1256ce330d9 100644 --- a/kratos/utilities/xml_utilities/xml_appended_data_element_wrapper.cpp +++ b/kratos/utilities/xml_utilities/xml_appended_data_element_wrapper.cpp @@ -128,7 +128,7 @@ void XmlAppendedDataElementWrapper::Write( rOStream.write(mData.data(), mData.size()); - rOStream << "\n"; + rOStream << std::endl; this->WriteElementTagEnd(rOStream, Level); } diff --git a/kratos/utilities/xml_utilities/xml_ascii_nd_data_element.cpp b/kratos/utilities/xml_utilities/xml_ascii_nd_data_element.cpp index 3d938d7a66f2..8ac3eb80773a 100644 --- a/kratos/utilities/xml_utilities/xml_ascii_nd_data_element.cpp +++ b/kratos/utilities/xml_utilities/xml_ascii_nd_data_element.cpp @@ -65,7 +65,7 @@ void XmlAsciiNDDataElement::Write( } } - rOStream << "\n"; + rOStream << std::endl; this->WriteElementTagEnd(rOStream, Level); } diff --git a/kratos/utilities/xml_utilities/xml_base64_binary_nd_data_element.cpp b/kratos/utilities/xml_utilities/xml_base64_binary_nd_data_element.cpp index 70e4f25a9da5..f3ed2b71622f 100644 --- a/kratos/utilities/xml_utilities/xml_base64_binary_nd_data_element.cpp +++ b/kratos/utilities/xml_utilities/xml_base64_binary_nd_data_element.cpp @@ -63,7 +63,7 @@ void XmlBase64BinaryNDDataElement::Write( base64_encoder.WriteData(span.begin(), span.size()); } - rOStream << "\n"; + rOStream << std::endl; this->WriteElementTagEnd(rOStream, Level); } diff --git a/kratos/utilities/xml_utilities/xml_element.cpp b/kratos/utilities/xml_utilities/xml_element.cpp index 45329948ede9..dd3a67847dd5 100644 --- a/kratos/utilities/xml_utilities/xml_element.cpp +++ b/kratos/utilities/xml_utilities/xml_element.cpp @@ -58,7 +58,7 @@ void XmlElement::WriteElementTagStart( rOStream << " " << r_pair.first << "=\"" << r_pair.second << "\""; } - rOStream << ">\n"; + rOStream << ">" << std::endl; } void XmlElement::WriteElementTagEnd( @@ -66,7 +66,7 @@ void XmlElement::WriteElementTagEnd( const IndexType Level) const { const std::string tabbing(Level * 3, ' '); - rOStream << tabbing << "\n"; + rOStream << tabbing << "" << std::endl; } void XmlElement::WriteEmptyElementTag( std::ostream& rOStream, @@ -80,7 +80,7 @@ void XmlElement::WriteEmptyElementTag( rOStream << " " << r_pair.first << "=\"" << r_pair.second << "\""; } - rOStream << "/>\n"; + rOStream << "/>" << std::endl; } } // namespace Kratos \ No newline at end of file From 4a6bcc2162695778632a88afb6a519720442fc08 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Tue, 24 Feb 2026 21:52:17 +0100 Subject: [PATCH 114/116] minor --- kratos/input_output/vtu_output.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/kratos/input_output/vtu_output.cpp b/kratos/input_output/vtu_output.cpp index d2fa78bd6438..8ebe1a88e983 100644 --- a/kratos/input_output/vtu_output.cpp +++ b/kratos/input_output/vtu_output.cpp @@ -741,7 +741,7 @@ std::string WritePartitionedUnstructuredGridData( // writing to file std::ofstream output_file; output_file.open(p_vtu_file_name, std::ios::out | std::ios::trunc); - output_file << "\n"; + output_file << "" << std::endl; p_vtu_file_element.Write(output_file); } @@ -1260,7 +1260,7 @@ std::pair VtuOutput::WriteUnstructuredGridData( // write the vtu file. std::ofstream output_file; output_file.open(output_vtu_file_name.str(), std::ios::out | std::ios::trunc | std::ios::binary); - output_file << "\n"; + output_file << "" << std::endl; vtk_file_element.Write(output_file); output_file.close(); @@ -1440,7 +1440,7 @@ std::pair VtuOutput::WriteIntegrationPointData( std::ofstream output_file; output_file.open(output_vtu_file_name.str(), std::ios::out | std::ios::trunc); - output_file << "\n"; + output_file << "" << std::endl; vtk_file_element.Write(output_file); output_file.close(); @@ -1594,7 +1594,7 @@ void VtuOutput::PrintOutput(const std::string& rOutputFileNamePrefix) std::ofstream output_file; output_file.open(rOutputFileNamePrefix + ".pvd", std::ios::out | std::ios::trunc); - output_file << "\n"; + output_file << "" << std::endl; pvd_file_element.Write(output_file); output_file.close(); } else { @@ -1626,7 +1626,7 @@ void VtuOutput::PrintOutput(const std::string& rOutputFileNamePrefix) } } - output_file << " \n\n"; + output_file << " " << std::endl <<"" << std::endl; output_file.close(); } From 63a10cfc50f156f2d355dc6f00c444b224b0f155 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya <7856520+sunethwarna@users.noreply.github.com> Date: Wed, 25 Feb 2026 08:30:20 +0100 Subject: [PATCH 115/116] add xml comparison --- .../tests/filtering/explicit_filters_tests.py | 2 +- .../compare_two_files_check_process.py | 29 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/applications/OptimizationApplication/tests/filtering/explicit_filters_tests.py b/applications/OptimizationApplication/tests/filtering/explicit_filters_tests.py index 063e0d3fc864..c6df1a350c7d 100644 --- a/applications/OptimizationApplication/tests/filtering/explicit_filters_tests.py +++ b/applications/OptimizationApplication/tests/filtering/explicit_filters_tests.py @@ -282,7 +282,7 @@ def __RunTestCase(self, filter_function_type: str, damping_function_type: str, r "reference_file_name" : "explicit_filter_reference_1.vtu.orig", "output_file_name" : "explicit_filter_reference.vtu", "remove_output_file" : true, - "comparison_type" : "deterministic" + "comparison_type" : "vtu" }""") params["reference_file_name"].SetString(ref_file) params["output_file_name"].SetString(f"output_{ref_file[:-4]}/test_elements_0.vtu") diff --git a/kratos/python_scripts/compare_two_files_check_process.py b/kratos/python_scripts/compare_two_files_check_process.py index d4895bacbcaf..25575014dd0c 100644 --- a/kratos/python_scripts/compare_two_files_check_process.py +++ b/kratos/python_scripts/compare_two_files_check_process.py @@ -10,6 +10,7 @@ import filecmp import os import math +import xml.etree.ElementTree def Factory(settings, current_model): if not isinstance(settings, KratosMultiphysics.Parameters): @@ -104,6 +105,8 @@ def ExecuteFinalize(self): self.__CompareDatFileVariablesTimeHistory() elif (self.comparison_type == "vtk"): self.__CompareVtkFile() + elif (self.comparison_type == "vtu") or (self.comparison_type == "xml"): + self.__CompareXmlFile() else: raise NameError('Requested comparison type "' + self.comparison_type + '" not implemented yet') @@ -532,6 +535,32 @@ def CompareFieldData(lines_ref, lines_out, line_counter, num_entities): if line_ref.startswith("POINT_DATA") or line_ref.startswith("CELL_DATA"): CompareData(lines_ref, lines_out, line_counter) + def __CompareXmlFile(self): + """This function compares vtu files + """ + if not os.path.isfile(self.reference_file_name): + raise RuntimeError(f"The reference file \"{self.reference_file_name}\" is not found.") + + if not os.path.isfile(self.output_file_name): + raise RuntimeError(f"The output file \"{self.output_file_name}\" is not found.") + + ref_xml = xml.etree.ElementTree.parse(self.reference_file_name) + out_xml = xml.etree.ElementTree.parse(self.output_file_name) + + def check_element(ref_element: xml.etree.ElementTree.Element, out_element: xml.etree.ElementTree.Element): + if ref_element.tag != out_element.tag: + raise RuntimeError(f"The element tag mismatch [ ref element tag = {ref_element.tag}, output element tag = {out_element.tag} ].") + + if ref_element.attrib != out_element.attrib: + raise RuntimeError(f"The element tag mismatch [ ref element tag = {ref_element.tag}, output element tag = {out_element.tag} ].\nRef attribs:\n{ref_element.attrib}\nOut attribs:\n{out_element.attrib}") + + if ref_element.text != out_element.text: + raise RuntimeError(f"Data mismatch [ ref element tag = {ref_element.tag}, out element tag = {out_element.tag} ].\nRef attribs:\n{ref_element.attrib}\nRef data:\n{ref_element.text}\nOut attribs:\n{out_element.attrib}\nOut data:\n{out_element.text}") + + check_element(ref_xml.getroot(), out_xml.getroot()) + for ref_sub_element, out_sub_element in zip(ref_xml.getroot().iter(), out_xml.getroot().iter()): + check_element(ref_sub_element, out_sub_element) + def __CheckCloseValues(self, val_a, val_b, additional_info=""): isclosethis = t_isclose(val_a, val_b, rel_tol=self.reltol, abs_tol=self.tol) full_msg = self.info_msg + "\n" From aaf485b4afffdceb2ee34b5f9c500a01a63c39d5 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya <7856520+sunethwarna@users.noreply.github.com> Date: Wed, 25 Feb 2026 11:10:55 +0100 Subject: [PATCH 116/116] update to vtu comparison --- .../test_optimization_problem_vtu_output_process.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/OptimizationApplication/tests/process_tests/test_optimization_problem_vtu_output_process.py b/applications/OptimizationApplication/tests/process_tests/test_optimization_problem_vtu_output_process.py index 9df77433413a..770d1f36b493 100644 --- a/applications/OptimizationApplication/tests/process_tests/test_optimization_problem_vtu_output_process.py +++ b/applications/OptimizationApplication/tests/process_tests/test_optimization_problem_vtu_output_process.py @@ -181,7 +181,7 @@ def test_OptimizationProblemVtuOutputProcess(self): "reference_file_name" : "test_1_orig.vtu", "output_file_name" : "Optimization_Results/test_1/test_1_elements_0.vtu", "remove_output_file" : true, - "comparison_type" : "deterministic" + "comparison_type" : "vtu" }""")).Execute() CompareTwoFilesCheckProcess(Kratos.Parameters(""" @@ -189,7 +189,7 @@ def test_OptimizationProblemVtuOutputProcess(self): "reference_file_name" : "test_2_orig.vtu", "output_file_name" : "Optimization_Results/test_2/test_2_elements_0.vtu", "remove_output_file" : true, - "comparison_type" : "deterministic" + "comparison_type" : "vtu" }""")).Execute() @classmethod