Skip to content

Commit

Permalink
Merge pull request #73 from oberbichler/feature/add-rotation-coupling
Browse files Browse the repository at this point in the history
Add rotation coupling
  • Loading branch information
oberbichler authored Jun 9, 2020
2 parents c54b3d0 + 07522aa commit 05bbea8
Show file tree
Hide file tree
Showing 7 changed files with 270 additions and 36 deletions.
57 changes: 38 additions & 19 deletions include/eqlib/Problem.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ class Problem {
ElementsF m_elements_f;
ElementsG m_elements_g;

std::vector<index> m_active_elements_f;
std::vector<index> m_active_elements_g;

Equations m_equations;
Variables m_variables;

Expand Down Expand Up @@ -93,6 +96,8 @@ class Problem {
, m_grainsize(grainsize)
, m_max_element_n(0)
, m_max_element_m(0)
, m_active_elements_f(length(m_elements_f))
, m_active_elements_g(length(m_elements_g))
{
Log::task_begin("Initialize problem...");

Expand Down Expand Up @@ -524,6 +529,25 @@ class Problem {
}

public: // methods: computation
void update_active_elements()
{
m_active_elements_f.clear();

for (index i = 0; i < nb_elements_f(); i++) {
if (m_elements_f[i]->is_active()) {
m_active_elements_f.emplace_back(i);
}
}

m_active_elements_g.clear();

for (index i = 0; i < nb_elements_g(); i++) {
if (m_elements_g[i]->is_active()) {
m_active_elements_g.emplace_back(i);
}
}
}

template <bool TParallel, bool TInfo, index TOrder>
void compute()
{
Expand All @@ -537,22 +561,17 @@ class Problem {

m_data.set_zero<TOrder>();

update_active_elements();

if constexpr (TParallel) {
ProblemData l_data(m_data);

std::vector<index> active_elements_f;

for (index i = 0; i < nb_elements_f(); i++) {
if (m_elements_f[i]->is_active()) {
active_elements_f.push_back(i);
}
}

#pragma omp parallel if (m_nb_threads != 1) num_threads(m_nb_threads) firstprivate(l_data)
{
#pragma omp for schedule(dynamic, m_grainsize) nowait
for (index i = 0; i < length(active_elements_f); i++) {
compute_element_f<TOrder>(l_data, active_elements_f[i]);
for (index i = 0; i < length(m_active_elements_f); i++) {
// Log::info("Element {}", i);
compute_element_f<TOrder>(l_data, m_active_elements_f[i]);
}

if (sigma() != 1.0) {
Expand All @@ -568,8 +587,8 @@ class Problem {
}

#pragma omp for schedule(dynamic, m_grainsize) nowait
for (index i = 0; i < nb_elements_g(); i++) {
compute_element_g<TOrder>(l_data, i);
for (index i = 0; i < length(m_active_elements_g); i++) {
compute_element_g<TOrder>(l_data, m_active_elements_g[i]);
}

#pragma omp critical
Expand Down Expand Up @@ -1381,26 +1400,26 @@ class Problem {
.def("remove_inactive_elements", &Type::remove_inactive_elements)
.def("compute", &Type::compute<true>, "order"_a = 2, py::call_guard<py::gil_scoped_release>())
.def("hm_add_diagonal", &Type::hm_add_diagonal, "value"_a)
.def("hm_inv_v", &Type::hm_inv_v)
.def("hm_inv_v", &Type::hm_inv_v, py::call_guard<py::gil_scoped_release>())
.def("hm_v", &Type::hm_v)
.def("f_of", [](Type& self, Ref<const Vector> x) {
self.set_x(x);
self.compute<false>(0);
return self.f();
},
"x"_a)
"x"_a, py::call_guard<py::gil_scoped_release>())
.def("g_of", [](Type& self, Ref<const Vector> x) {
self.set_x(x);
self.compute<false>(0);
return Vector(self.g());
},
"x"_a)
"x"_a, py::call_guard<py::gil_scoped_release>())
.def("df_of", [](Type& self, Ref<const Vector> x) {
self.set_x(x);
self.compute<false>(1);
return Vector(self.df());
},
"x"_a)
"x"_a, py::call_guard<py::gil_scoped_release>())
.def("dg_of", [=](Type& self, Ref<const Vector> x) {
self.set_x(x);
self.compute<false>(1);
Expand All @@ -1409,7 +1428,7 @@ class Problem {
std::make_pair(self.nb_equations(), self.nb_variables()))
.release();
},
"x"_a)
"x"_a, py::call_guard<py::gil_scoped_release>())
.def("hm_of", [=](Type& self, Ref<const Vector> x) {
self.set_x(x);
self.compute<false>(2);
Expand All @@ -1418,13 +1437,13 @@ class Problem {
std::make_pair(self.nb_variables(), self.nb_variables()))
.release();
},
"x"_a)
"x"_a, py::call_guard<py::gil_scoped_release>())
.def("hm_v_of", [=](Type& self, Ref<const Vector> x, Ref<const Vector> p) {
self.set_x(x);
self.compute<false>(2);
return self.hm_v(p);
},
"x"_a, "p"_a)
"x"_a, "p"_a, py::call_guard<py::gil_scoped_release>())
.def("scale", &Type::scale, "factor"_a);
}
};
Expand Down
24 changes: 11 additions & 13 deletions include/eqlib/objectives/IgaNormalDistanceAD.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,26 +66,24 @@ class IgaNormalDistanceAD : public Objective {
auto result = Scalar3hj::zero(nb_variables());

for (const auto& [shape_functions_a, shape_functions_b, weight] : m_data) {
const Vector3hj a1_a = evaluate_act_geometry_hj_a(m_nodes_a, shape_functions_a.row(1), nb_variables());
const Vector3hj a2_a = evaluate_act_geometry_hj_a(m_nodes_a, shape_functions_a.row(2), nb_variables());
const auto a1_a = evaluate_act_geometry_hj_a(m_nodes_a, shape_functions_a.row(1), nb_variables());
const auto a2_a = evaluate_act_geometry_hj_a(m_nodes_a, shape_functions_a.row(2), nb_variables());

const Vector3hj n_a = a1_a.cross(a2_a);
const Vector3hj a3_a = n_a / n_a.norm();
const auto a3_a = a1_a.cross(a2_a).normalized();

const Vector3hj a1_b = evaluate_act_geometry_hj_b(m_nodes_b, shape_functions_b.row(1), nb_variables());
const Vector3hj a2_b = evaluate_act_geometry_hj_b(m_nodes_b, shape_functions_b.row(2), nb_variables());
const auto a1_b = evaluate_act_geometry_hj_b(m_nodes_b, shape_functions_b.row(1), nb_variables());
const auto a2_b = evaluate_act_geometry_hj_b(m_nodes_b, shape_functions_b.row(2), nb_variables());

const Vector3hj n_b = a1_b.cross(a2_b);
const Vector3hj a3_b = n_b / n_b.norm();
const auto a3_b = a1_b.cross(a2_b).normalized();

const Vector3hj delta = a3_b - a3_a;
const auto delta = a3_b - a3_a;

result += (delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2]) * weight / 2;
result += delta.dot(delta) * weight;
}

g = result.g();
h = result.h();
return result.f();
g = result.g() / 2;
h = result.h() / 2;
return result.f() / 2;
}

double compute(Ref<Vector> g, Ref<Matrix> h) const override
Expand Down
8 changes: 4 additions & 4 deletions include/eqlib/objectives/IgaPointDistanceAD.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,12 @@ class IgaPointDistanceAD : public Objective {

const auto delta = x_a - x_b;

result += delta.squaredNorm() * weight / 2;
result += delta.squaredNorm() * weight;
}

g = result.g();
h = result.h();
return result.f();
g = result.g() / 2;
h = result.h() / 2;
return result.f() / 2;
}

double compute(Ref<Vector> g, Ref<Matrix> h) const override
Expand Down
138 changes: 138 additions & 0 deletions include/eqlib/objectives/IgaRotationCouplingAD.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
#pragma once

#include "IgaUtilities.h"

#include "../Node.h"
#include "../Objective.h"

#include <hyperjet/hyperjet.h>

namespace eqlib {

class IgaRotationCouplingAD : public Objective {
private: // types
using Type = IgaRotationCouplingAD;

struct Data {
Matrix shape_functions_a;
Matrix shape_functions_b;
Vector3D ref_a3_a;
Vector3D ref_a3_b;
Vector3D axis;
double weight;
};

private: // variables
std::vector<Pointer<Node>> m_nodes_a;
std::vector<Pointer<Node>> m_nodes_b;
std::vector<Data> m_data;

public: // constructor
IgaRotationCouplingAD(
std::vector<Pointer<Node>> nodes_a,
std::vector<Pointer<Node>> nodes_b)
: m_nodes_a(nodes_a)
, m_nodes_b(nodes_b)
{
m_variables.reserve(length(nodes_a) * 3 + length(nodes_b) * 3);

for (const auto node : nodes_a) {
m_variables.push_back(node->x());
m_variables.push_back(node->y());
m_variables.push_back(node->z());
}

for (const auto node : nodes_b) {
m_variables.push_back(node->x());
m_variables.push_back(node->y());
m_variables.push_back(node->z());
}
}

public: // methods
index add(const Matrix shape_functions_a, const Matrix shape_functions_b, const Vector3D axis, const double weight)
{
using namespace iga_utilities;

const Vector3D ref_a1_a = evaluate_ref_geometry(m_nodes_a, shape_functions_a.row(1));
const Vector3D ref_a2_a = evaluate_ref_geometry(m_nodes_a, shape_functions_a.row(2));
const Vector3D ref_a3_a = ref_a1_a.cross(ref_a2_a).normalized();

const Vector3D ref_a1_b = evaluate_ref_geometry(m_nodes_b, shape_functions_b.row(1));
const Vector3D ref_a2_b = evaluate_ref_geometry(m_nodes_b, shape_functions_b.row(2));
const Vector3D ref_a3_b = ref_a1_b.cross(ref_a2_b).normalized();

const Vector3D unit_axis = axis.normalized();

m_data.emplace_back<Data>({shape_functions_a, shape_functions_b, ref_a3_a, ref_a3_b, unit_axis, weight});
return m_data.size() - 1;
}

template <int TOrder>
double compute(Ref<Vector> g, Ref<Matrix> h) const
{
using namespace eqlib::iga_utilities;
using Space = hyperjet::Space<2, double, -1>;

static_assert(0 <= TOrder && TOrder <= 2);

auto result = Space::Scalar::zero(nb_variables());

for (const auto& [shape_functions_a, shape_functions_b, ref_a3_a, ref_a3_b, axis, weight] : m_data) {
const auto a1_a = evaluate_act_geometry_hj_a(m_nodes_a, shape_functions_a.row(1), nb_variables());
const auto a2_a = evaluate_act_geometry_hj_a(m_nodes_a, shape_functions_a.row(2), nb_variables());

const auto a3_a = a1_a.cross(a2_a).normalized();

const auto a1_b = evaluate_act_geometry_hj_b(m_nodes_b, shape_functions_b.row(1), nb_variables());
const auto a2_b = evaluate_act_geometry_hj_b(m_nodes_b, shape_functions_b.row(2), nb_variables());

const auto a3_b = a1_b.cross(a2_b).normalized();

const auto w_a = a3_a - ref_a3_a.transpose();
const auto w_b = a3_b - ref_a3_b.transpose();

const auto omega_a = ref_a3_a.cross(w_a);
const auto omega_b = ref_a3_b.cross(w_b);

const auto angle_a = omega_a.dot(axis).asin();
const auto angle_b = omega_b.dot(axis).asin();

const auto angular_difference = angle_a - angle_b;

result += angular_difference.pow(2) * weight;
}

g = result.g() / 2;
h = result.h() / 2;
return result.f() / 2;
}

double compute(Ref<Vector> g, Ref<Matrix> h) const override
{
if (g.size() == 0) {
return compute<0>(g, h);
} else if (h.size() == 0) {
return compute<1>(g, h);
} else {
return compute<2>(g, h);
}
}

public: // python
template <typename TModule>
static void register_python(TModule& m)
{
namespace py = pybind11;
using namespace pybind11::literals;

using Holder = Pointer<Type>;
using Base = Objective;

py::class_<Type, Base, Holder>(m, "IgaRotationCouplingAD")
.def(py::init<std::vector<Pointer<Node>>, std::vector<Pointer<Node>>>(), "nodes_a"_a, "nodes_b"_a)
.def("add", &Type::add, "shape_functions"_a, "shape_functions_b"_a, "axis"_a, "weight"_a);
}
}; // class IgaRotationCouplingAD

} // namespace eqlib
4 changes: 4 additions & 0 deletions src/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <eqlib/objectives/IgaPointDistance.h>
#include <eqlib/objectives/IgaPointDistanceAD.h>
#include <eqlib/objectives/IgaPointLocation.h>
#include <eqlib/objectives/IgaRotationCouplingAD.h>
#include <eqlib/objectives/IgaShell3PAD.h>

PYBIND11_MODULE(eqlib, m)
Expand Down Expand Up @@ -120,6 +121,9 @@ PYBIND11_MODULE(eqlib, m)
// objectives: IgaPointLocation
eqlib::IgaPointLocation::register_python(m);

// objectives: IgaRotationCouplingAD
eqlib::IgaRotationCouplingAD::register_python(m);

// objectives: IgaShell3PAD
eqlib::IgaShell3PAD::register_python(m);
}
Loading

0 comments on commit 05bbea8

Please sign in to comment.