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.
150 lines
6.0 KiB
150 lines
6.0 KiB
#ifndef MEDUSA_BITS_DOMAINS_BASICRELAX_FWD_HPP_
|
|
#define MEDUSA_BITS_DOMAINS_BASICRELAX_FWD_HPP_
|
|
|
|
#include <medusa/Config.hpp>
|
|
#include <medusa/bits/types/Range_fwd.hpp>
|
|
|
|
/**
|
|
* @file
|
|
* Declaration of class for domain relaxation.
|
|
*
|
|
* @example test/domains/BasicRelax_test.cpp
|
|
*/
|
|
|
|
namespace mm {
|
|
|
|
|
|
/**
|
|
* Redistributes nodes towards more uniform distribution by minimizing potential between nodes. The
|
|
* engine first finds `num_neighbours` closest neighbours. Then it translates each point according
|
|
* to the repelling "force" induced by its neighbours, where it also takes into account target
|
|
* potential. The force is determined by summing the gradients of potentials in surrounding nodes,
|
|
* where amplitude is determined based on distance to the closest neighbour and supplied target
|
|
* density function. The algorithm uses also a primitive Simulated Annealing, i.e.\ the relax
|
|
* movement magnitude is multiplied with an annealing factor that is linearly dropping from
|
|
* initial_heat to final_heat.
|
|
*
|
|
* The Engine supports two call types: with supplied distribution function relax(func), where it
|
|
* tries to satisfy the user supplied nodal density function. This can be achieved only when there
|
|
* is the total number of domain nodes the same as integral of density function over the domain. If
|
|
* there is too much nodes a volatile relax might occur. If there is not enough nodes the relax
|
|
* might become lazy. The best use of this mode is in combination with fillDistribution Engines,
|
|
* check test for examples.
|
|
*
|
|
* Without distribution, where nodes always move towards less populated area regardless anything.
|
|
* The relax magnitude is simply determined from annealing factor and distance to the closest node.
|
|
* A simple and stable approach, however, note that this relax always converges towards uniformly
|
|
* distributed nodes.
|
|
*
|
|
* Usage example:
|
|
* @snippet domains/BasicRelax_test.cpp BasicRelax usage example
|
|
* @ingroup domains
|
|
*/
|
|
class BasicRelax {
|
|
public:
|
|
/// Indicating type of projection used when a relax node goes out of the domain.
|
|
enum ProjectionType {
|
|
/**
|
|
* Escaped nodes are frozen outside the domain till the end of relax and
|
|
* then removed. This is good option for violent and unstable relaxations.
|
|
*/
|
|
DO_NOT_PROJECT,
|
|
/**
|
|
* Project on boundary in relax movement direction. In general produces better
|
|
* distribution on boundaries, but the approximated normals can be bad.
|
|
*/
|
|
PROJECT_IN_DIRECTION,
|
|
/**
|
|
* Project between two closest boundary nodes – this one might result in divergent
|
|
* behaviour, when both closest nodes are on one side, leading in huge gaps on the
|
|
* boundary. However, when there are enough boundary nodes in the first place, this
|
|
* works very well.
|
|
*/
|
|
PROJECT_BETWEEN_CLOSEST
|
|
};
|
|
|
|
private:
|
|
int num_neighbours = 1; ///< Number of nodes to consider when calculating the potential.
|
|
int num_iterations = 50; ///< Number of iterations performed.
|
|
double initial_heat = 1; ///< Initial heat, usually between 0 and 5.
|
|
double final_heat = 0; ///< Heat at the end of the relax, usually around 0.
|
|
int potential_order = 2; ///< Order of repulsing potential.
|
|
int rebuild_tree_after = 1; ///< How often engine rebuild search tree, 1 is perfect but slow.
|
|
Range<int> nodes_; ///< List of nodes to process.
|
|
ProjectionType projection_type = DO_NOT_PROJECT; ///< On boundary projection method.
|
|
double boundary_projection_threshold = 0.75; ///< Threshold for projecting nodes on boundary.
|
|
|
|
public:
|
|
BasicRelax() = default;
|
|
|
|
/// Move only given nodes.
|
|
BasicRelax& onlyNodes(Range<int> nodes);
|
|
|
|
/**
|
|
* Sets initial heat.
|
|
* @param in Initial heat, usually between 0 and 5, higher heat
|
|
* means more volatile movement. High initial heat may cause divergence and erratic behaviour.
|
|
* Setting too small initial heat might results in lazy relaxation.
|
|
*/
|
|
BasicRelax& initialHeat(double in);
|
|
|
|
/// Sets final heat.
|
|
BasicRelax& finalHeat(double in);
|
|
|
|
/// Sets num neighbours.
|
|
BasicRelax& numNeighbours(int neighbours);
|
|
|
|
/// Sets order of repulsing potential
|
|
BasicRelax& potentialOrder(int order);
|
|
|
|
/// Sets number of iterations.
|
|
BasicRelax& iterations(int iterations);
|
|
|
|
/**
|
|
* Sets rebuild tree frequency. Ir rebuild's tree every `in` iterations.
|
|
* `in = 1` is perfect but slow. Using higher values results in better
|
|
* performance at the cost of accuracy.
|
|
*/
|
|
BasicRelax& rebuildTreeAfter(int iterations);
|
|
|
|
/// Determines how to handle nodes that escape during relaxation.
|
|
BasicRelax& projectionType(ProjectionType in);
|
|
|
|
/**
|
|
* Sets threshold for adding nodes on boundary, i.e.\ if node @f$d_1@f$ and @f$d_2@f$
|
|
* are distances to closest boundary nodes, do not add node on boundary if
|
|
* @f$d_1/d_2 < boundary_projection_threshold @f$.
|
|
* If threshold is 0 all nodes are added, if it is greater than 1 no nodes are added.
|
|
*/
|
|
BasicRelax& boundaryProjectionThreshold(double in);
|
|
|
|
/**
|
|
* Runs the relax on the selected domain with constant distribution equals
|
|
* to domain characteristic distance
|
|
* @param domain domain to process
|
|
*/
|
|
template<class domain_t>
|
|
void operator()(domain_t& domain) const {
|
|
typedef typename domain_t::vector_t vec_t;
|
|
operator()(domain, [](const vec_t& /* p */) { return -1.0; });
|
|
}
|
|
|
|
/**
|
|
* Runs the relax on the selected domain with constant density
|
|
* @param domain domain to process
|
|
* @param r constant density
|
|
*/
|
|
template<class domain_t>
|
|
void operator()(domain_t& domain, double r) const {
|
|
typedef typename domain_t::vector_t vec_t;
|
|
operator()(domain, [r](const vec_t& /* p */) { return r; });
|
|
}
|
|
|
|
/// Runs the procedure of a given domain.
|
|
template<class domain_t, class radius_func_type>
|
|
void operator()(domain_t& domain, const radius_func_type& r_func) const;
|
|
}; // class BasicRelax
|
|
|
|
} // namespace mm
|
|
|
|
#endif // MEDUSA_BITS_DOMAINS_BASICRELAX_FWD_HPP_
|
|
|