Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions kratos/python/add_tensor_adaptors_to_python.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "tensor_adaptors/geometries_tensor_adaptor.h"
#include "tensor_adaptors/tensor_adaptor.h"
#include "tensor_adaptors/variable_tensor_adaptor.h"
#include "tensor_adaptors/geometry_metrics_tensor_adaptor.h"

// Include base h
#include "add_tensor_adaptors_to_python.h"
Expand Down Expand Up @@ -303,6 +304,27 @@ void AddTensorAdaptorsToPython(pybind11::module& m)
.def(py::init<const ConnectivityIdsTensorAdaptor::BaseType&, const bool>(),
py::arg("tensor_adaptor"),
py::arg("copy") = true);

py::class_<GeometryMetricsTensorAdaptor, GeometryMetricsTensorAdaptor::Pointer, GeometryMetricsTensorAdaptor::BaseType> geometric_tensor_adaptor(tensor_adaptor_sub_module, "GeometryMetricsTensorAdaptor");

py::enum_<GeometryMetricsTensorAdaptor::Metric>(geometric_tensor_adaptor,"Metric")
.value("DomainSize", GeometryMetricsTensorAdaptor::Metric::DomainSize)
.export_values();

geometric_tensor_adaptor
.def(py::init<const GeometryMetricsTensorAdaptor::BaseType&, GeometryMetricsTensorAdaptor::Metric, const bool>(),
py::arg("tensor_adaptor"),
py::arg("datum"),
py::arg("copy") = true)
.def(py::init<ModelPart::GeometryContainerType::Pointer, GeometryMetricsTensorAdaptor::Metric>(),
py::arg("container"),
py::arg("datum"))
.def(py::init<ModelPart::ConditionsContainerType::Pointer, GeometryMetricsTensorAdaptor::Metric>(),
py::arg("container"),
py::arg("datum"))
.def(py::init<ModelPart::ElementsContainerType::Pointer, GeometryMetricsTensorAdaptor::Metric>(),
py::arg("container"),
py::arg("datum"));
}

} // namespace Kratos::Python.
158 changes: 158 additions & 0 deletions kratos/tensor_adaptors/geometry_metrics_tensor_adaptor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
// | / |
// ' / __| _` | __| _ \ __|
// . \ | ( | | ( |\__ `
// _|\_\_| \__,_|\__|\___/ ____/
// Multi-Physics
//
// License: BSD License
// Kratos default license: kratos/license.txt
//
// Main authors: Suneth Warnakulasuriya
//

// System includes
#include <unordered_map>

// 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<unsigned int> GetShape(
const unsigned int NumberOfEntities,
const GeometryMetricsTensorAdaptor::Metric CurrentMetric)
{
switch (CurrentMetric) {
case GeometryMetricsTensorAdaptor::DomainSize:
return DenseVector<unsigned int>(1, NumberOfEntities);
}

return DenseVector<unsigned int>(0);
}

template<class TEntityType>
const ModelPart::GeometryType& GetGeometry(const TEntityType& rEntity)
{
if constexpr(std::is_same_v<TEntityType, ModelPart::GeometryType>) {
return rEntity;
} else {
return rEntity.GetGeometry();
}
}

template<class TContainerType>
void FillDomainSize(
Kratos::span<double> DataSpan,
const TContainerType& rContainer)
{
IndexPartition<IndexType>(rContainer.size()).for_each([&rContainer, &DataSpan](const auto Index) {
DataSpan[Index] = GetGeometry(*(rContainer.begin() + Index)).DomainSize();
});
}

template<class TContainerType>
void FillData(
Kratos::span<double> DataSpan,
const GeometryMetricsTensorAdaptor::Metric CurrentMetric,
const TContainerType& rContainer)
{
switch (CurrentMetric) {
case GeometryMetricsTensorAdaptor::DomainSize:
FillDomainSize(DataSpan, rContainer);
break;
}
}

} // namespace GeometryMetricsTensorAdaptorHelperUtils

template<class TContainerPointerType>
GeometryMetricsTensorAdaptor::GeometryMetricsTensorAdaptor(
TContainerPointerType pContainer,
const Metric CurrentMetric)
: mMetric(CurrentMetric)
{
this->mpContainer = pContainer;
this->mpStorage = Kratos::make_shared<Storage>(DenseVector<unsigned int>(1, pContainer->size()));
}

GeometryMetricsTensorAdaptor::GeometryMetricsTensorAdaptor(
const TensorAdaptor& rOther,
const Metric CurrentMetric,
const bool Copy)
: BaseType(rOther, Copy),
mMetric(CurrentMetric)
{
KRATOS_TRY

if (!HoldsAlternative<ModelPart::GeometryContainerType::Pointer, ModelPart::ConditionsContainerType::Pointer,
ModelPart::ElementsContainerType::Pointer>::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], CurrentMetric);

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("");
}

TensorAdaptor<double>::Pointer GeometryMetricsTensorAdaptor::Clone() const
{
return Kratos::make_shared<GeometryMetricsTensorAdaptor>(*this);
}

void GeometryMetricsTensorAdaptor::CollectData()
{
KRATOS_TRY

std::visit([this](auto pContainer) {
using container_type = BareType<decltype(*pContainer)>;
if constexpr(IsInList<container_type, ModelPart::GeometryContainerType, ModelPart::ConditionsContainerType, ModelPart::ElementsContainerType>) {
GeometryMetricsTensorAdaptorHelperUtils::FillData(this->ViewData(), this->mMetric, *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:";
info << " Metric = ";
switch (mMetric) {
case DomainSize: info << "DomainSize"; break;
}
info << ", " << BaseType::Info();
return info.str();
}

template KRATOS_API(KRATOS_CORE) GeometryMetricsTensorAdaptor::GeometryMetricsTensorAdaptor(ModelPart::GeometryContainerType::Pointer, GeometryMetricsTensorAdaptor::Metric);
template KRATOS_API(KRATOS_CORE) GeometryMetricsTensorAdaptor::GeometryMetricsTensorAdaptor(ModelPart::ConditionsContainerType::Pointer, GeometryMetricsTensorAdaptor::Metric);
template KRATOS_API(KRATOS_CORE) GeometryMetricsTensorAdaptor::GeometryMetricsTensorAdaptor(ModelPart::ElementsContainerType::Pointer, GeometryMetricsTensorAdaptor::Metric);

} // namespace Kratos
122 changes: 122 additions & 0 deletions kratos/tensor_adaptors/geometry_metrics_tensor_adaptor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// | / |
// ' / __| _` | __| _ \ __|
// . \ | ( | | ( |\__ `
// _|\_\_| \__,_|\__|\___/ ____/
// Multi-Physics
//
// License: BSD License
// Kratos default license: kratos/license.txt
//
// Main authors: Suneth Warnakulasuriya
//

#pragma once

// System includes
#include <string>

// External includes

// Project includes
#include "tensor_adaptors/tensor_adaptor.h"

namespace Kratos {

///@name Kratos Classes
///@{

/**
* @ingroup TensorAdaptors
* @brief Adaptor class for calculating geometry metrics.
*
* @details This class provides an interface to calculate geometry metrics for given entity container pointer @p pContainer .
* This @ref TensorAdaptor only implements the @ref CollectData method. Following geometry metrics are supported.
* - @ref GeometryMetricsTensorAdaptor::DomainSize
*
* @section GeometryMetricsTensorAdaptor_supported_container Supported entity container types
* - @ref ModelPart::GeometryContainerType
* - @ref ModelPart::ConditionsContainerType
* - @ref ModelPart::ElementsContainerType
*
* @section GeometryMetricsTensorAdaptor_usage Usage
* - Use @ref CollectData to fill internal data with the metric from each entity given by the container pointer @p pContainer .
*
* @author Suneth Warnakulasuriya
* @see @ref TensorAdaptor Base class.
*/
class KRATOS_API(KRATOS_CORE) GeometryMetricsTensorAdaptor: public TensorAdaptor<double> {
public:
///@name Enums
///@{

enum class Metric
{
DomainSize
};

///@}
///@name Type definitions
///@{

KRATOS_CLASS_POINTER_DEFINITION(GeometryMetricsTensorAdaptor);

using BaseType = TensorAdaptor<double>;

using enum Metric;

///@}
///@name Life cycle
///@{

template<class TContainerPointerType>
GeometryMetricsTensorAdaptor(
TContainerPointerType pContainer,
const Metric Datum);

GeometryMetricsTensorAdaptor(
const TensorAdaptor& rOther,
const Metric Datum,
const bool Copy = true);

// Destructor
~GeometryMetricsTensorAdaptor() override = default;

///@}
///@name Public operations
///@{

/**
* @brief Clones the existing tensor adaptor.
*/
TensorAdaptor::Pointer Clone() const override;

/**
* @brief Fill the internal data with metric of the entities in the container.
*/
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
///@{

Metric mMetric;

///@}
};

/// @}
} // namespace Kratos
26 changes: 26 additions & 0 deletions kratos/tests/test_tensor_adaptors.py
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,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()
Expand Down
Loading