You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
406 lines
16 KiB
406 lines
16 KiB
#ifndef MEDUSA_BITS_DOMAINS_BOXSHAPE_HPP_
|
|
#define MEDUSA_BITS_DOMAINS_BOXSHAPE_HPP_
|
|
|
|
/**
|
|
* @file
|
|
* Implementation of class for box shaped domains.
|
|
*/
|
|
|
|
#include "BoxShape_fwd.hpp"
|
|
#include <medusa/bits/utils/assert.hpp>
|
|
#include "DomainDiscretization.hpp"
|
|
#include "discretization_helpers.hpp"
|
|
#include "DomainShape.hpp"
|
|
#include "GeneralFill.hpp"
|
|
#include <medusa/bits/utils/numutils.hpp>
|
|
#include <medusa/bits/types/Vec.hpp>
|
|
|
|
namespace mm
|
|
{
|
|
|
|
template <typename vec_t>
|
|
BoxShape<vec_t>::BoxShape(vec_t beg, vec_t end) : beg_(beg), end_(end)
|
|
{
|
|
for (int i = 0; i < dim; ++i)
|
|
{
|
|
assert_msg(std::abs(beg_[i] - end_[i]) >= margin_,
|
|
"Box has no volume, sides in dimension %d have same coordinate %g.",
|
|
i, beg_[i]);
|
|
if (beg_[i] > end_[i])
|
|
std::swap(beg_[i], end_[i]);
|
|
}
|
|
}
|
|
|
|
template <typename vec_t>
|
|
bool BoxShape<vec_t>::contains(const vec_t &point) const
|
|
{
|
|
for (int i = 0; i < dim; ++i)
|
|
{
|
|
if (!(beg_[i] - margin_ <= point[i] && point[i] <= end_[i] + margin_))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
template <typename vec_t>
|
|
DomainDiscretization<vec_t> BoxShape<vec_t>::discretizeBoundaryWithStep(scalar_t step,
|
|
int type) const
|
|
{
|
|
Vec<int, dim> counts;
|
|
for (int i = 0; i < dim; ++i)
|
|
counts[i] = iceil((end_[i] - beg_[i]) / step) + 1;
|
|
return discretizeBoundary(counts, type);
|
|
}
|
|
|
|
template <typename vec_t>
|
|
DomainDiscretization<vec_t> BoxShape<vec_t>::discretizeBoundary(const Vec<int, dim> &counts,
|
|
int type) const
|
|
{
|
|
for (int x : counts)
|
|
{
|
|
assert_msg(x >= 2, "All counts must be greater than 2, got counts = %s", counts);
|
|
}
|
|
DomainDiscretization<vec_t> domain(*this);
|
|
vec_t normal, point;
|
|
if (dim == 1)
|
|
{
|
|
domain.addBoundaryNode(beg_, type == 0 ? -1 : type, vec_t(-1.0));
|
|
domain.addBoundaryNode(end_, type == 0 ? -2 : type, vec_t(1.0));
|
|
}
|
|
else if (dim == 2)
|
|
{
|
|
const int TOP = (type == 0) ? -4 : type;
|
|
const int RIGHT = (type == 0) ? -2 : type;
|
|
const int BOTTOM = (type == 0) ? -3 : type;
|
|
const int LEFT = (type == 0) ? -1 : type;
|
|
|
|
scalar_t step = (end_[0] - beg_[0]) / (counts[0] - 1);
|
|
for (int i = 1; i < counts[0] - 1; ++i)
|
|
{
|
|
point[0] = beg_[0] + i * step;
|
|
point[1] = beg_[1];
|
|
normal[0] = 0;
|
|
normal[1] = -1;
|
|
domain.addBoundaryNode(point, BOTTOM, normal);
|
|
point[1] = end_[1];
|
|
normal[0] = 0;
|
|
normal[1] = 1;
|
|
domain.addBoundaryNode(point, TOP, normal);
|
|
}
|
|
step = (end_[1] - beg_[1]) / (counts[1] - 1);
|
|
for (int i = 1; i < counts[1] - 1; ++i)
|
|
{
|
|
point[1] = beg_[1] + i * step;
|
|
point[0] = beg_[0];
|
|
normal[0] = -1;
|
|
normal[1] = 0;
|
|
domain.addBoundaryNode(point, LEFT, normal);
|
|
point[0] = end_[0];
|
|
normal[0] = 1;
|
|
normal[1] = 0;
|
|
domain.addBoundaryNode(point, RIGHT, normal);
|
|
}
|
|
domain.addBoundaryNode(beg_, LEFT, vec_t({-1, -1}).normalized());
|
|
domain.addBoundaryNode(end_, RIGHT, vec_t({1, 1}).normalized());
|
|
domain.addBoundaryNode(vec_t({beg_[0], end_[1]}), TOP, vec_t({-1, 1}).normalized());
|
|
domain.addBoundaryNode(vec_t({end_[0], beg_[1]}), BOTTOM, vec_t({1, -1}).normalized());
|
|
}
|
|
else if (dim == 3)
|
|
{
|
|
int LEFT = -1, RIGHT = -2, FRONT = -3, BACK = -4, BOTTOM = -5, TOP = -6;
|
|
if (type != 0)
|
|
LEFT = RIGHT = FRONT = BACK = BOTTOM = TOP = type;
|
|
scalar_t step = (end_[0] - beg_[0]) / (counts[0] - 1); // x
|
|
for (int i = 1; i < counts[0] - 1; ++i)
|
|
{
|
|
point[0] = beg_[0] + i * step;
|
|
point[1] = beg_[1];
|
|
point[2] = beg_[2];
|
|
normal = vec_t({0, -1, -1}).normalized();
|
|
domain.addBoundaryNode(point, BOTTOM, normal);
|
|
point[1] = beg_[1];
|
|
point[2] = end_[2];
|
|
normal = vec_t({0, -1, 1}).normalized();
|
|
domain.addBoundaryNode(point, FRONT, normal);
|
|
point[1] = end_[1];
|
|
point[2] = beg_[2];
|
|
normal = vec_t({0, 1, -1}).normalized();
|
|
domain.addBoundaryNode(point, BACK, normal);
|
|
point[1] = end_[1];
|
|
point[2] = end_[2];
|
|
normal = vec_t({0, 1, 1}).normalized();
|
|
domain.addBoundaryNode(point, TOP, normal);
|
|
|
|
scalar_t inner_step = (end_[1] - beg_[1]) / (counts[1] - 1); // y
|
|
for (int j = 1; j < counts[1] - 1; ++j)
|
|
{
|
|
point[1] = beg_[1] + j * inner_step;
|
|
point[2] = beg_[2];
|
|
normal = vec_t({0, 0, -1});
|
|
domain.addBoundaryNode(point, BOTTOM, normal);
|
|
point[2] = end_[2];
|
|
normal = vec_t({0, 0, 1});
|
|
domain.addBoundaryNode(point, TOP, normal);
|
|
}
|
|
inner_step = (end_[2] - beg_[2]) / (counts[2] - 1); // z
|
|
for (int j = 1; j < counts[2] - 1; ++j)
|
|
{
|
|
point[2] = beg_[2] + j * inner_step;
|
|
point[1] = beg_[1];
|
|
normal = vec_t({0, -1, 0});
|
|
domain.addBoundaryNode(point, FRONT, normal);
|
|
point[1] = end_[1];
|
|
normal = vec_t({0, 1, 0});
|
|
domain.addBoundaryNode(point, BACK, normal);
|
|
}
|
|
}
|
|
step = (end_[1] - beg_[1]) / (counts[1] - 1); // y
|
|
for (int i = 1; i < counts[1] - 1; ++i)
|
|
{
|
|
point[1] = beg_[1] + i * step;
|
|
point[0] = beg_[0];
|
|
point[2] = beg_[2];
|
|
normal = vec_t({-1, 0, -1}).normalized();
|
|
domain.addBoundaryNode(point, LEFT, normal);
|
|
point[0] = beg_[0];
|
|
point[2] = end_[2];
|
|
normal = vec_t({-1, 0, 1}).normalized();
|
|
domain.addBoundaryNode(point, TOP, normal);
|
|
point[0] = end_[0];
|
|
point[2] = beg_[2];
|
|
normal = vec_t({1, 0, -1}).normalized();
|
|
domain.addBoundaryNode(point, BOTTOM, normal);
|
|
point[0] = end_[0];
|
|
point[2] = end_[2];
|
|
normal = vec_t({1, 0, 1}).normalized();
|
|
domain.addBoundaryNode(point, RIGHT, normal);
|
|
|
|
scalar_t inner_step = (end_[2] - beg_[2]) / (counts[2] - 1); // z
|
|
for (int j = 1; j < counts[2] - 1; ++j)
|
|
{
|
|
point[2] = beg_[2] + j * inner_step;
|
|
point[0] = beg_[0];
|
|
normal = vec_t({-1, 0, 0});
|
|
domain.addBoundaryNode(point, LEFT, normal);
|
|
point[0] = end_[0];
|
|
normal = vec_t({1, 0, 0});
|
|
domain.addBoundaryNode(point, RIGHT, normal);
|
|
}
|
|
}
|
|
step = (end_[2] - beg_[2]) / (counts[2] - 1); // z
|
|
for (int i = 1; i < counts[2] - 1; ++i)
|
|
{
|
|
point[2] = beg_[2] + i * step;
|
|
point[0] = beg_[0];
|
|
point[1] = beg_[1];
|
|
normal = vec_t({-1, -1, 0}).normalized();
|
|
domain.addBoundaryNode(point, FRONT, normal);
|
|
point[0] = beg_[0];
|
|
point[1] = end_[1];
|
|
normal = vec_t({-1, 1, 0}).normalized();
|
|
domain.addBoundaryNode(point, LEFT, normal);
|
|
point[0] = end_[0];
|
|
point[1] = beg_[1];
|
|
normal = vec_t({1, -1, 0}).normalized();
|
|
domain.addBoundaryNode(point, RIGHT, normal);
|
|
point[0] = end_[0];
|
|
point[1] = end_[1];
|
|
normal = vec_t({1, 1, 0}).normalized();
|
|
domain.addBoundaryNode(point, BACK, normal);
|
|
}
|
|
domain.addBoundaryNode(beg_, BOTTOM, vec_t({-1, -1, -1}).normalized());
|
|
domain.addBoundaryNode(end_, TOP, vec_t({1, 1, 1}).normalized());
|
|
domain.addBoundaryNode(vec_t({end_[0], beg_[1], beg_[2]}), BOTTOM,
|
|
vec_t({1, -1, -1}).normalized());
|
|
domain.addBoundaryNode(vec_t({beg_[0], end_[1], end_[2]}), TOP,
|
|
vec_t({-1, 1, 1}).normalized());
|
|
domain.addBoundaryNode(vec_t({end_[0], end_[1], beg_[2]}), BACK,
|
|
vec_t({1, 1, -1}).normalized());
|
|
domain.addBoundaryNode(vec_t({beg_[0], end_[1], beg_[2]}), LEFT,
|
|
vec_t({-1, 1, -1}).normalized());
|
|
domain.addBoundaryNode(vec_t({beg_[0], beg_[1], end_[2]}), FRONT,
|
|
vec_t({-1, -1, 1}).normalized());
|
|
domain.addBoundaryNode(vec_t({end_[0], beg_[1], end_[2]}), RIGHT,
|
|
vec_t({1, -1, 1}).normalized());
|
|
}
|
|
return domain;
|
|
}
|
|
|
|
template <typename vec_t>
|
|
std::ostream &BoxShape<vec_t>::print(std::ostream &os) const
|
|
{
|
|
return os << "BoxShape(" << beg_.transpose() << ", " << end_.transpose() << ")";
|
|
}
|
|
|
|
template <typename vec_t>
|
|
DomainDiscretization<vec_t>
|
|
BoxShape<vec_t>::discretizeBoundaryWithDensity(const std::function<scalar_t(vec_t)> &dr,
|
|
int type) const
|
|
{
|
|
static_assert(0 <= dim && dim <= 3, "Only dimensions up to 3 are supported.");
|
|
DomainDiscretization<vec_t> domain(*this);
|
|
if (dim == 1)
|
|
{
|
|
domain.addBoundaryNode(beg_, type == 0 ? -1 : type, vec_t(-1.0));
|
|
domain.addBoundaryNode(end_, type == 0 ? -2 : type, vec_t(1.0));
|
|
}
|
|
else if (dim == 2)
|
|
{
|
|
const int TOP = (type == 0) ? -4 : type;
|
|
const int RIGHT = (type == 0) ? -2 : type;
|
|
const int BOTTOM = (type == 0) ? -3 : type;
|
|
const int LEFT = (type == 0) ? -1 : type;
|
|
|
|
vec_t p1 = beg_;
|
|
vec_t p2 = {beg_[0], end_[1]};
|
|
vec_t p3 = end_;
|
|
vec_t p4 = {end_[0], beg_[1]};
|
|
|
|
for (const auto &p : discretization_helpers::discretizeLineWithDensity(p1, p2, dr))
|
|
{
|
|
domain.addBoundaryNode(p, LEFT, {-1, 0});
|
|
}
|
|
for (const auto &p : discretization_helpers::discretizeLineWithDensity(p2, p3, dr))
|
|
{
|
|
domain.addBoundaryNode(p, TOP, {0, 1});
|
|
}
|
|
for (const auto &p : discretization_helpers::discretizeLineWithDensity(p3, p4, dr))
|
|
{
|
|
domain.addBoundaryNode(p, RIGHT, {1, 0});
|
|
}
|
|
for (const auto &p : discretization_helpers::discretizeLineWithDensity(p4, p1, dr))
|
|
{
|
|
domain.addBoundaryNode(p, BOTTOM, {0, -1});
|
|
}
|
|
|
|
domain.addBoundaryNode(p1, LEFT, vec_t({-1, -1}).normalized());
|
|
domain.addBoundaryNode(p2, TOP, vec_t({-1, 1}).normalized());
|
|
domain.addBoundaryNode(p3, RIGHT, vec_t({1, 1}).normalized());
|
|
domain.addBoundaryNode(p4, BOTTOM, vec_t({1, -1}).normalized());
|
|
}
|
|
else if (dim == 3)
|
|
{
|
|
int LEFT = -1, RIGHT = -2, FRONT = -3, BACK = -4, BOTTOM = -5, TOP = -6;
|
|
if (type != 0)
|
|
LEFT = RIGHT = FRONT = BACK = BOTTOM = TOP = type;
|
|
Vec<scalar_t, 2> side_beg, side_end;
|
|
GeneralFill<Vec<scalar_t, 2>> fill;
|
|
fill.seed(0).proximityTolerance(0.99);
|
|
{
|
|
side_beg[0] = beg_[1];
|
|
side_beg[1] = beg_[2];
|
|
side_end[0] = end_[1];
|
|
side_end[1] = end_[2];
|
|
BoxShape<Vec<scalar_t, 2>> side(side_beg, side_end);
|
|
auto dr2 = [&](const Vec<scalar_t, 2> &p)
|
|
{ return dr({beg_[0], p[0], p[1]}); };
|
|
auto domain2d = side.discretizeWithDensity(dr2, fill);
|
|
vec_t pos;
|
|
pos[0] = beg_[0];
|
|
for (int i : domain2d.interior())
|
|
{
|
|
pos[1] = domain2d.pos(i, 0);
|
|
pos[2] = domain2d.pos(i, 1);
|
|
domain.addBoundaryNode(pos, LEFT, {-1, 0, 0});
|
|
}
|
|
auto dr22 = [&](const Vec<scalar_t, 2> &p)
|
|
{ return dr({end_[0], p[0], p[1]}); };
|
|
domain2d = side.discretizeWithDensity(dr22, fill);
|
|
pos[0] = end_[0];
|
|
for (int i : domain2d.interior())
|
|
{
|
|
pos[1] = domain2d.pos(i, 0);
|
|
pos[2] = domain2d.pos(i, 1);
|
|
domain.addBoundaryNode(pos, RIGHT, {1, 0, 0});
|
|
}
|
|
}
|
|
{
|
|
side_beg[0] = beg_[0];
|
|
side_beg[1] = beg_[2];
|
|
side_end[0] = end_[0];
|
|
side_end[1] = end_[2];
|
|
BoxShape<Vec<scalar_t, 2>> side(side_beg, side_end);
|
|
auto dr2 = [&](const Vec<scalar_t, 2> &p)
|
|
{ return dr({p[0], beg_[1], p[1]}); };
|
|
auto domain2d = side.discretizeWithDensity(dr2, fill);
|
|
vec_t pos;
|
|
pos[1] = beg_[1];
|
|
for (int i : domain2d.interior())
|
|
{
|
|
pos[0] = domain2d.pos(i, 0);
|
|
pos[2] = domain2d.pos(i, 1);
|
|
domain.addBoundaryNode(pos, FRONT, {0, -1, 0});
|
|
}
|
|
auto dr22 = [&](const Vec<scalar_t, 2> &p)
|
|
{ return dr({p[0], end_[1], p[1]}); };
|
|
domain2d = side.discretizeWithDensity(dr22, fill);
|
|
pos[1] = end_[1];
|
|
for (int i : domain2d.interior())
|
|
{
|
|
pos[0] = domain2d.pos(i, 0);
|
|
pos[2] = domain2d.pos(i, 1);
|
|
domain.addBoundaryNode(pos, BACK, {0, 1, 0});
|
|
}
|
|
}
|
|
{
|
|
side_beg[0] = beg_[0];
|
|
side_beg[1] = beg_[1];
|
|
side_end[0] = end_[0];
|
|
side_end[1] = end_[1];
|
|
BoxShape<Vec<scalar_t, 2>> side(side_beg, side_end);
|
|
auto dr2 = [&](const Vec<scalar_t, 2> &p)
|
|
{ return dr({p[0], p[1], beg_[2]}); };
|
|
auto domain2d = side.discretizeWithDensity(dr2, fill);
|
|
vec_t pos;
|
|
pos[2] = beg_[2];
|
|
for (int i : domain2d.interior())
|
|
{
|
|
pos[0] = domain2d.pos(i, 0);
|
|
pos[1] = domain2d.pos(i, 1);
|
|
domain.addBoundaryNode(pos, BOTTOM, {0, 0, -1});
|
|
}
|
|
auto dr22 = [&](const Vec<scalar_t, 2> &p)
|
|
{ return dr({p[0], p[1], end_[2]}); };
|
|
domain2d = side.discretizeWithDensity(dr22, fill);
|
|
pos[2] = end_[2];
|
|
for (int i : domain2d.interior())
|
|
{
|
|
pos[0] = domain2d.pos(i, 0);
|
|
pos[1] = domain2d.pos(i, 1);
|
|
domain.addBoundaryNode(pos, TOP, {0, 0, 1});
|
|
}
|
|
}
|
|
}
|
|
return domain;
|
|
}
|
|
|
|
template <typename vec_t>
|
|
DomainDiscretization<vec_t> BoxShape<vec_t>::discretizeWithStep(
|
|
scalar_t step, int internal_type, int boundary_type) const
|
|
{
|
|
Vec<int, dim> counts;
|
|
for (int i = 0; i < dim; ++i)
|
|
counts[i] = iceil((end_[i] - beg_[i]) / step) + 1;
|
|
return discretize(counts, internal_type, boundary_type);
|
|
}
|
|
|
|
template <typename vec_t>
|
|
DomainDiscretization<vec_t> BoxShape<vec_t>::discretize(
|
|
const Vec<int, dim> &counts, int internal_type, int boundary_type) const
|
|
{
|
|
auto domain = discretizeBoundary(counts, boundary_type);
|
|
Vec<int, dim> counts_internal = counts - Vec<int, dim>::Constant(2);
|
|
if (internal_type == 0)
|
|
internal_type = 1;
|
|
for (const vec_t &p : linspace(beg_, end_, counts_internal, false))
|
|
{
|
|
domain.addInternalNode(p, internal_type);
|
|
}
|
|
return domain;
|
|
}
|
|
|
|
} // namespace mm
|
|
|
|
#endif // MEDUSA_BITS_DOMAINS_BOXSHAPE_HPP_
|
|
|