diff --git a/src/geometry/block.cc b/src/geometry/block.cc index 76795bd..0f6f72c 100644 --- a/src/geometry/block.cc +++ b/src/geometry/block.cc @@ -1,365 +1,367 @@ #include "block.hh" #include "block_surface_manipulations.hh" #include #include #include #include #include #include #include #include #include #include class BlockException: public std::exception { public: BlockException(std::stringstream & _what):what_stream(_what.str()) {}; BlockException(std::string &_what):what_stream(_what) {}; ~BlockException() throw() {}; virtual const char* what() const throw() { return this->what_stream.c_str(); } private: std::string what_stream; }; template Block::Block(const std::vector & _min_max, std::string _name) :Geometry(_name) { if (_min_max.size() != 2*DIM) { std::stringstream error; error << "The length of 'min_max' should be = " << 2*DIM; throw BlockException(error); } for (Uint i = 0 ; i < 2*DIM ; ++i) { this->min_max[i] = _min_max[i]; } } template Block::Block(const Real * min_max, std::string _name) :Geometry(_name) { for (Uint i = 0; i < 2 * DIM; ++i) { this->min_max[i] = min_max[i]; } } template Block::Block(const Block & other) :Geometry(other.name) { for (Uint i = 0 ; i < 2 * DIM ; ++i) { this->min_max[i] = other.min_max[i]; } } template void Block::shift(const PointRef & offset) { for (Uint i = 0 ; i < DIM ; ++i) { this->min_max[2 * i + 0] += offset.getComponent(i); this->min_max[2 * i + 1] += offset.getComponent(i); } } template InsideObject Block::from_border(const Real * point, Real tol) const { Real lower_violation = -std::numeric_limits::max(); Real upper_violation = -std::numeric_limits::max(); for (Uint i = 0; i < DIM; ++i) { keep_max(lower_violation, this->min_max[2*i] - point[i]); keep_max(upper_violation, point[i] - this->min_max[2*i+1]); } return {max(lower_violation, upper_violation), max(lower_violation-tol, upper_violation+tol) <= 0}; } template inline void in_direction_helper(Real & min_val, Real & max_val, const Real * direction, Real * point) { Real dot_prod = 0; Real norm = 0; for (Uint i = 0; i < DIM; ++i) { dot_prod += point[i] * direction[i]; norm += direction[i] * direction[i]; } dot_prod /= sqrt(norm); if (eval_min) { keep_min(min_val, dot_prod); } if (eval_max) { keep_max(max_val, dot_prod); } } template Real Block::min_in_direction(const Real * dir, const Real & unit) const { Real point[DIM]; Real min_val = std::numeric_limits::max(); for (Uint i = 0; i < 2; ++i) { point[0] = min_max[i]; for (Uint j = 0; j < 2; ++j) { point[1] = min_max[2 + j]; if (DIM == 3) { for (Uint k = 0; k < 2; ++k) { point[2] = min_max[4 + k]; in_direction_helper(min_val, min_val, dir, point); } } else if (DIM == 2) { in_direction_helper(min_val, min_val, dir, point); } } } return min_val/unit; } template Real Block::max_in_direction(const Real * dir, const Real & unit) const { Real point[DIM]; Real max_val = -std::numeric_limits::max(); for (Uint i = 0; i < 2; ++i) { point[0] = min_max[i]; for (Uint j = 0; j < 2; ++j) { point[1] = min_max[2 + j]; if (DIM == 3) { for (Uint k = 0; k < 2; ++k) { point[2] = min_max[4 + k]; in_direction_helper(max_val, max_val, dir, point); } } else if (DIM == 2) { in_direction_helper(max_val, max_val, dir, point); } } } return max_val/unit; } template Real Block::size_in_direction(const Real * dir, const Real & unit) const { Real point[DIM]; Real min_val = std::numeric_limits::max(); Real max_val = -std::numeric_limits::max(); for (Uint i = 0; i < 2; ++i) { point[0] = min_max[i]; for (Uint j = 0; j < 2; ++j) { point[1] = min_max[2 + j]; if (DIM == 3) { for (Uint k = 0; k < 2; ++k) { point[2] = min_max[4 + k]; in_direction_helper(min_val, max_val, dir, point); } } else if (DIM == 2) { in_direction_helper(min_val, max_val, dir, point); } } } return (max_val - min_val)/unit; } template void Block::printself(std::ostream & stream, int indent) const { indent_space(stream, indent); stream << "Block " << this->get_name() << ": " << std::endl; indent_space(stream, indent); stream << "x_min " << this->min_max[0] << ", x_max = " << this->min_max[1] << std::endl; indent_space(stream, indent); stream << "y_min " << this->min_max[2] << ", y_max = " << this->min_max[3] << std::endl; if (DIM == 3) { indent_space(stream, indent); stream << "z_min " << this->min_max[4] << ", z_max = " << this->min_max[5] << std::endl; } } template inline void enforce_slave(const PointRef & point, const Mesh & auxiliary, const std::vector & refinement, const Real & step_size, PointContainer & points) { Real ref_sq = step_size * auxiliary.interpolate(point, refinement); ref_sq *= ref_sq; std::deque delete_points; for (Uint point_id = 0 ; point_id < points.getSize() ; ++point_id) { if (ref_sq > distance2(point, points.getPoint(point_id))) { delete_points.push_front(point_id); } } auto point_it = delete_points.begin(); const auto point_end = delete_points.end(); for(; point_it != point_end; ++point_it) { points.deletePoint(*point_it); } points.addPoint(point); } template inline bool masterdom(const PointRef & point, const Real * min_max, const bool periodicity[DIM], bool master[DIM], bool & slave) { bool is_master = false; bool is_not_master = false; slave = false; for (Uint i = 0 ; i < DIM ; ++i) { master[i] = (point[i] == min_max[2*i]) && periodicity[i]; // not a master if i'm at the max of any periodic direction is_not_master |= (point[i] == min_max[2*i + 1]) && periodicity[i]; is_master |= master[i]; slave |= (point[i] == min_max[2*i + 1]) && periodicity[i]; } return is_master && !is_not_master; } template inline void drive_slaves(const PointRef & point, const Real * min_max, const bool periodicity[DIM], const Mesh & auxiliary, const std::vector & refinement, const Real & step_size, PointContainer & points) { bool master[DIM]; bool slave; if (masterdom(point, min_max, periodicity, master, slave)) { PointContainer slaves; slaves.addPoint(point); PointRef tmp; for (Uint i = 0 ; i < DIM ; ++i) { if ( master[i]) { Uint current_nb_slaves = slaves.getSize(); for (Uint slave_num = 0 ; slave_num < current_nb_slaves ; ++slave_num) { tmp = slaves.getConstPoint(slave_num); tmp[i] += min_max[2*i+1]-min_max[2*i]; slaves.addPoint(tmp); } } } for (Uint slave_num = 0 ; slave_num < slaves.getSize() ; ++slave_num) { enforce_slave(slaves.getConstPoint(slave_num), auxiliary, refinement, step_size, points); } } else if (!slave) { points.addPoint(point); } } template inline void micro_add_surface_point(PointRef & point_hi, PointRef & point_lo, const Uint xi, const Real * min_max, const Mesh & auxiliary, const std::vector & refinement, const bool periodicity[DIM], const Real & repr_const, PointContainer & points) { point_hi[xi] = point_lo[xi] = min_max[2*xi]; if (check_if_ok(point_lo, auxiliary, refinement, repr_const, points)) { drive_slaves(point_lo, min_max, periodicity, auxiliary, refinement, repr_const, points); } if (check_if_ok(point_hi, auxiliary, refinement, repr_const, points)) { drive_slaves(point_hi, min_max, periodicity, auxiliary, refinement, repr_const, points); } point_hi[xi] = point_lo[xi] = min_max[2*xi+1]; if (!periodicity[xi]) { add_if_ok(point_hi, auxiliary, refinement, repr_const, points); add_if_ok(point_lo, auxiliary, refinement, repr_const, points); } } template void recurse_through_dimensions(PointRef & point, const Uint xi, const Uint my_offset_dim, const Real * min_max, const Mesh & auxiliary, const std::vector & refinement, const bool periodicity[DIM], const Real step_size[DIM], const Real & repr_const, PointContainer & points, Uint * starts) { Uint my_dim = (xi+my_offset_dim) % DIM; Real length = min_max[2*my_dim + 1] - min_max[2*my_dim]; Uint nb_steps = length/step_size[my_dim]; PointRef point_lo = point; PointRef point_hi = point; // We mesh from the outside inwards, to make sure that corners/edges get // points for (Uint step = starts[my_offset_dim-1]; step < nb_steps/2+1; ++step) { point_lo[my_dim] = min_max[2*my_dim] + step * step_size[my_dim]; point_hi[my_dim] = min_max[2*my_dim + 1] - step * step_size[my_dim]; if (DIM == my_offset_dim + 1) { micro_add_surface_point(point_hi, point_lo, xi, min_max, auxiliary, refinement, periodicity, repr_const, points); } else { recurse_through_dimensions(point_lo, xi, my_offset_dim + 1, min_max, auxiliary, refinement, periodicity, step_size, repr_const, points, starts); recurse_through_dimensions(point_hi, xi, my_offset_dim + 1, min_max, auxiliary, refinement, periodicity, step_size, repr_const, points, starts); } } } template void Block::generate_surface_points(const Mesh & auxiliary, const std::vector & refinement, const Real step_size[DIM], const Real & repr_const, const bool periodicity[DIM], PointContainer & points) const { PointRef point; Uint starts[DIM] = {0}; for (Uint xi = 0 ; xi < DIM ; ++xi) { starts[DIM-1-xi] = 1; recurse_through_dimensions(point, xi, 1, this->min_max, auxiliary, refinement, periodicity, step_size, repr_const, points, starts); } points.cleanDuplicates(1.); } template void Block::complement_periodically(const Mesh & auxiliary, const std::vector & refinement, const PointContainer & points, PointContainer & complement, int direction, Uint dim) const { // relevant coordinate of the good and the bad side Real ok_coord, bad_coord; if (direction > 0) { ok_coord = this->min_max[2*dim + 0]; bad_coord = this->min_max[2*dim + 1]; } else { ok_coord = this->min_max[2*dim + 1]; bad_coord = this->min_max[2*dim + 0]; } Real tol = std::max(fabs(ok_coord), 1.); tol = 2000*tol*std::numeric_limits::epsilon(); PointRef point; - for (Uint i = 0; i < points.getSize() ; ++i) { - point = points.getConstPoint(i); + + PointContainer container = points + complement; + for (Uint i = 0; i < container.getSize() ; ++i) { + point = container.getConstPoint(i); if (fabs(point.getComponent(dim) - ok_coord) < tol) { point.getArray()[dim] = bad_coord; add_periodic_complement(auxiliary, refinement, point, points, complement); } } } template class Block; template class Block; diff --git a/src/geometry/geometry.hh b/src/geometry/geometry.hh index eb30156..f16f85f 100644 --- a/src/geometry/geometry.hh +++ b/src/geometry/geometry.hh @@ -1,212 +1,212 @@ /** * @file geometry.hh * @author Till Junge * @date Wed Apr 4 15:15:10 2012 * * @brief Geometry motherclass (interface) for CADD mesher * * @section LICENSE * * * */ /* -------------------------------------------------------------------------- */ #ifndef __GEOMETRY_HH__ #define __GEOMETRY_HH__ #include "common.hh" #include "point_container.hh" #include //#include "cadd_mesh.hh" template class Mesh; struct InsideObject { Real distance; bool is_inside; }; /*! \brief Geometry interface for CADD mesher * You will never use this class.*/ template class Geometry { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: /*! Constructor *\param _name a string identifier for the geometry */ Geometry(std::string _name = ""):name(_name){}; virtual ~Geometry(){}; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// function to print the content of the class virtual void printself(std::ostream & stream, int indent = 0) const { stream << "This is just a interface class and this function should never " << "ever be called" < & offset) = 0; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ /// returns the string identifier const std::string & get_name() const { return this->name; } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ public: /*! creates a copy of the object (calling new) and returns a Geometry * pointer*/ virtual Geometry * resolveType() const = 0; /*! test whether a point is inside the domain * \param point coordinates of the point to test*/ virtual bool is_inside(const Real * point, Real tol) const = 0; bool py_is_inside(const PointRef & point, Real tol) const { return this->is_inside(point, tol); } virtual inline bool is_inside(const PointRef & point, Real tol) const { return this->is_inside(&(point.getComponent(0)), tol);} /*! Returns the minimum value of all constraint violations (negative return * value means point is inside and return value from the nearest boundary) * \param point coordintates of the point to test*/ virtual InsideObject from_border(const Real * point, Real tol) const = 0; inline InsideObject from_border(const PointRef & point, Real tol) const { return this->from_border(&(point.getComponent(0)), tol);} /*! projects the geometry on a line of direction \a dir and returns the * minimum of the line segment spanned * \param dir direction vector (will be scaled to unity by the method * \param unit unit in which the distance should be expressed, by default unity*/ virtual Real min_in_direction(const Real * dir, const Real & unit = 1) const = 0; /*! projects the geometry on a line of direction \a dir and returns the * maximum of the line segment spanned * \param dir direction vector (will be scaled to unity by the method * \param unit unit in which the distance should be expressed, by default unity*/ virtual Real max_in_direction(const Real * dir, const Real & unit = 1) const = 0; /*! projects the geometry on a line of direction \a dir and returns the length * of the projection * \param dir direction vector (will be scaled to unity by the method * \param unit unit in which the distance should be expressed, by default unity*/ virtual Real size_in_direction(const Real * dir, const Real & unit = 1) const ; /*! put nodes onto the surface of the geometry * \param auxiliary mesh for refinement interpolation * \param refinement vector of refinements used with the auxiliary mesh * \param step_size array of periodic cell sizes as returned by * lattice::getSpatialConstants() * \param repr_const representative constant of the periodic cell * \param periodicity self-explanatory * \param points container of nodal points for meshing */ virtual void generate_surface_points(const Mesh & auxiliary, const std::vector & refinement, const Real step_size[DIM], const Real & repr_const, const bool periodicity[DIM], PointContainer & points) const; /*! When the dimensions of the overall geometry are not a power of two times * the lattice size, the domain can be not filled correctly. This method * corrects the fucked up side by periodically repeating the ok side. * \param direction positive values mean that the min side is used to augment * the max size, negative values the inverse. * \param dim dimension to fix: 0:x, 1:y, 2:z */ virtual void complement_periodically(const Mesh & auxiliary, const std::vector & refinement, const PointContainer & points, PointContainer & complement, int direction, Uint dim) const; protected: std::string name; }; /// standard output stream operator template inline std::ostream & operator <<(std::ostream & stream, const Geometry & _this) { _this.printself(stream); return stream; } /* -------------------------------------------------------------------------- */ template Geometry * newGeom(const subGeom & geometry) { return static_cast*>(new subGeom(geometry)); } /* -------------------------------------------------------------------------- */ template inline bool check_if_ok(const PointRef & point, const Mesh & auxiliary, const std::vector & refinement, const Real & step_size, PointContainer & points) { Real ref_sq = square(step_size * auxiliary.interpolate(point, refinement)); Real step_sq = step_size*step_size; // if refinement is smaller than 1 => full resolution if (ref_sq < step_sq) { return false; } // check whether the new point in too close to an existing point for (Uint point_id = 0; point_id < points.getSize() ; ++point_id) { if (ref_sq > distance2(point, points.getPoint(point_id))) { return false; } } return true; } /* -------------------------------------------------------------------------- */ template inline bool add_if_ok(const PointRef & point, const Mesh & auxiliary, const std::vector & refinement, const Real & step_size, PointContainer & points) { if (check_if_ok(point, auxiliary, refinement, step_size, points)) { points.addPoint(point); return true; } else { return false; } } /* -------------------------------------------------------------------------- */ template bool add_periodic_complement(const Mesh & auxiliary, const std::vector & refinement, - const PointRef point, + const PointRef & point, const PointContainer & points, PointContainer & complement) { Real local_refinement = auxiliary.interpolate(point, refinement); if (local_refinement <= 1.) { complement.addPoint(point); return true; } else { return false; } } #endif /* __GEOMETRY_HH__ */