Dcpse.hpp 27.99 KiB
//
// DCPSE Created by tommaso on 29/03/19.
// Modified, Updated and Maintained by Abhinav and Pietro
//Surface Operators by Abhinav Singh on 07/10/2021
#ifndef OPENFPM_PDATA_DCPSE_HPP
#define OPENFPM_PDATA_DCPSE_HPP
#ifdef HAVE_EIGEN
#include "Vector/vector_dist.hpp"
#include "MonomialBasis.hpp"
#include "DMatrix/EMatrix.hpp"
#include "SupportBuilder.hpp"
#include "Support.hpp"
#include "Vandermonde.hpp"
#include "DcpseDiagonalScalingMatrix.hpp"
#include "DcpseRhs.hpp"
#include "hash_map/hopscotch_map.h"
template<unsigned int N> struct value_t {};
template<bool cond>
struct is_scalar {
template<typename op_type>
static auto
analyze(const vect_dist_key_dx &key, op_type &o1) -> typename std::remove_reference<decltype(o1.value(
key))>::type {
return o1.value(key);
};
};
template<>
struct is_scalar<false> {
template<typename op_type>
static auto
analyze(const vect_dist_key_dx &key, op_type &o1) -> typename std::remove_reference<decltype(o1.value(
key))>::type {
return o1.value(key);
};
};
template<unsigned int dim, typename vector_type,typename vector_type2=vector_type>
class Dcpse {
public:
typedef typename vector_type::stype T;
typedef typename vector_type::value_type part_type;
typedef vector_type vtype;
#ifdef SE_CLASS1
int update_ctr=0;
#endif
protected:
const Point<dim, unsigned int> differentialSignature;
const unsigned int differentialOrder;
const MonomialBasis<dim> monomialBasis;
bool isSharedLocalSupport = false;
openfpm::vector<Support> localSupports; // Each MPI rank has just access to the local ones
openfpm::vector<T> localEps; // Each MPI rank has just access to the local ones
openfpm::vector<T> localEpsInvPow; // Each MPI rank has just access to the local ones
openfpm::vector<size_t> kerOffsets;
openfpm::vector<T> calcKernels;
openfpm::vector<T> nSpacings;
vector_type & particlesFrom;
vector_type2 & particlesTo;
double rCut,supportSizeFactor=1;
unsigned int convergenceOrder;
support_options opt;
public:
// This works in this way:
// 1) User constructs this by giving a domain of points (where one of the properties is the value of our f),
// the signature of the differential operator and the error order bound.
// 2) The machinery for assembling and solving the linear system for coefficients starts...
// 3) The user can then call an evaluate(point) method to get the evaluation of the differential operator
// on the given point.
////c=HOverEpsilon. Note that the Eps value is computed by <h>/c (<h>=local average spacing for each particle and its support). This factor c is used in the Vandermonde.hpp.
double HOverEpsilon=0.9;
#ifdef SE_CLASS1
int getUpdateCtr() const
{
return update_ctr;
}
#endif
// Here we require the first element of the aggregate to be:
// 1) the value of the function f on the point
Dcpse(vector_type &particles,
Point<dim, unsigned int> differentialSignature,
unsigned int convergenceOrder,
T rCut,
T supportSizeFactor = 1, //Maybe change this to epsilon/h or h/epsilon = c 0.9. Benchmark
support_options opt = support_options::RADIUS)
:particlesFrom(particles),
particlesTo(particles),
differentialSignature(differentialSignature),
differentialOrder(Monomial<dim>(differentialSignature).order()),
monomialBasis(differentialSignature.asArray(), convergenceOrder),
opt(opt)
{
particles.ghost_get_subset(); // This communicates which ghost particles to be excluded from support
initializeStaticSize(particles, particles, convergenceOrder, rCut, supportSizeFactor);
}
Dcpse(vector_type &particles,
const Dcpse<dim, vector_type>& other,
Point<dim, unsigned int> differentialSignature,
unsigned int convergenceOrder,
T rCut,
T supportSizeFactor = 1,
support_options opt = support_options::RADIUS)
:particlesFrom(particles), particlesTo(particles), opt(opt),
differentialSignature(differentialSignature),
differentialOrder(Monomial<dim>(differentialSignature).order()),
monomialBasis(differentialSignature.asArray(), convergenceOrder),
localSupports(other.localSupports),
isSharedLocalSupport(true)
{
particles.ghost_get_subset();
initializeStaticSize(particles, particles, convergenceOrder, rCut, supportSizeFactor);
}
Dcpse(vector_type &particlesFrom,vector_type2 &particlesTo,
Point<dim, unsigned int> differentialSignature,
unsigned int convergenceOrder,
T rCut,
T supportSizeFactor = 1,
support_options opt = support_options::RADIUS)
:particlesFrom(particlesFrom),particlesTo(particlesTo),
differentialSignature(differentialSignature),
differentialOrder(Monomial<dim>(differentialSignature).order()),
monomialBasis(differentialSignature.asArray(), convergenceOrder),
opt(opt)
{
particlesFrom.ghost_get_subset();
initializeStaticSize(particlesFrom,particlesTo,convergenceOrder, rCut, supportSizeFactor);
}
// Default constructor to call from SurfaceDcpse
// to initialize protected members
Dcpse(
vector_type &particles,
Point<dim, unsigned int> differentialSignature,
unsigned int convergenceOrder,
support_options opt)
:
particlesFrom(particles),
particlesTo(particles),
differentialSignature(differentialSignature),
differentialOrder(Monomial<dim>(differentialSignature).order()),
monomialBasis(differentialSignature.asArray(), convergenceOrder),
opt(opt)
{}
template<unsigned int prp>
void DrawKernel(vector_type &particles, int k)
{
Support support = localSupports.get(k);
size_t xpK = k;
size_t kerOff = kerOffsets.get(k);
auto & keys = support.getKeys();
for (int i = 0 ; i < keys.size() ; i++)
{
size_t xqK = keys.get(i);
particles.template getProp<prp>(xqK) += calcKernels.get(kerOff+i);
}
}
template<unsigned int prp>
void DrawKernelNN(vector_type &particles, int k)
{
Support support = localSupports.get(k);
size_t xpK = k;
size_t kerOff = kerOffsets.get(k);
auto & keys = support.getKeys();
for (int i = 0 ; i < keys.size() ; i++)
{
size_t xqK = keys.get(i);
particles.template getProp<prp>(xqK) = 1.0;
}
}
template<unsigned int prp>
void DrawKernel(vector_type &particles, int k, int i)
{
Support support = localSupports.get(k);
size_t xpK = k;
size_t kerOff = kerOffsets.get(k);
auto & keys = support.getKeys();
for (int i = 0 ; i < keys.size() ; i++)
{
size_t xqK = keys.get(i);
particles.template getProp<prp>(xqK)[i] += calcKernels.get(kerOff+i);
}
}
/*
* breif Particle to Particle Interpolation Evaluation
*/
template<unsigned int prp1,unsigned int prp2>
void p2p()
{
typedef typename std::remove_reference<decltype(particlesTo.template getProp<prp2>(0))>::type T2;
auto it = particlesTo.getDomainIterator();
auto supportsIt = localSupports.begin();
auto epsItInvPow = localEpsInvPow.begin();
while (it.isNext()){
double epsInvPow = *epsItInvPow;
T2 Dfxp = 0;
Support support = *supportsIt;
size_t xpK = support.getReferencePointKey();
//Point<dim, typename vector_type::stype> xp = particlesTo.getPos(xpK);
//T fxp = sign * particlesTo.template getProp<fValuePos>(xpK);
size_t kerOff = kerOffsets.get(xpK);
auto & keys = support.getKeys();
for (int i = 0 ; i < keys.size() ; i++)
{
size_t xqK = keys.get(i);
T2 fxq = particlesFrom.template getProp<prp1>(xqK);
Dfxp += fxq * calcKernels.get(kerOff+i);
}
Dfxp = epsInvPow*Dfxp;
//
//T trueDfxp = particles.template getProp<2>(xpK);
// Store Dfxp in the right position
particlesTo.template getProp<prp2>(xpK) = Dfxp;
//
++it;
++supportsIt;
++epsItInvPow;
}
}
/*! \brief Save the DCPSE computations
*
*/
void save(const std::string &file){
auto & v_cl=create_vcluster();
size_t req = 0;
Packer<decltype(localSupports),HeapMemory>::packRequest(localSupports,req);
Packer<decltype(localEps),HeapMemory>::packRequest(localEps,req);
Packer<decltype(localEpsInvPow),HeapMemory>::packRequest(localEpsInvPow,req);
Packer<decltype(calcKernels),HeapMemory>::packRequest(calcKernels,req);
Packer<decltype(kerOffsets),HeapMemory>::packRequest(kerOffsets,req);
// allocate the memory
HeapMemory pmem;
//pmem.allocate(req);
ExtPreAlloc<HeapMemory> mem(req,pmem);
//Packing
Pack_stat sts;
Packer<decltype(localSupports),HeapMemory>::pack(mem,localSupports,sts);
Packer<decltype(localEps),HeapMemory>::pack(mem,localEps,sts);
Packer<decltype(localEpsInvPow),HeapMemory>::pack(mem,localEpsInvPow,sts);
Packer<decltype(calcKernels),HeapMemory>::pack(mem,calcKernels,sts);
Packer<decltype(kerOffsets),HeapMemory>::pack(mem,kerOffsets,sts);
// Save into a binary file
std::ofstream dump (file+"_"+std::to_string(v_cl.rank()), std::ios::out | std::ios::binary);
if (dump.is_open() == false)
{ std::cerr << __FILE__ << ":" << __LINE__ <<" Unable to write since dump is open at rank "<<v_cl.rank()<<std::endl;
return;
}
dump.write ((const char *)pmem.getPointer(), pmem.size());
return;
}
/*! \brief Load the DCPSE computations
*
*
*/
void load(const std::string & file)
{
auto & v_cl=create_vcluster();
std::ifstream fs (file+"_"+std::to_string(v_cl.rank()), std::ios::in | std::ios::binary | std::ios::ate );
if (fs.is_open() == false)
{
std::cerr << __FILE__ << ":" << __LINE__ << " error, opening file: " << file << std::endl;
return;
}
// take the size of the file
size_t sz = fs.tellg();
fs.close();
// reopen the file without ios::ate to read
std::ifstream input (file+"_"+std::to_string(v_cl.rank()), std::ios::in | std::ios::binary );
if (input.is_open() == false)
{//some message here maybe
return;}
// Create the HeapMemory and the ExtPreAlloc memory
size_t req = 0;
req += sz;
HeapMemory pmem;
ExtPreAlloc<HeapMemory> mem(req,pmem);
mem.allocate(pmem.size());
// read
input.read((char *)pmem.getPointer(), sz);
//close the file
input.close();
//Unpacking
Unpack_stat ps;
Unpacker<decltype(localSupports),HeapMemory>::unpack(mem,localSupports,ps);
Unpacker<decltype(localEps),HeapMemory>::unpack(mem,localEps,ps);
Unpacker<decltype(localEpsInvPow),HeapMemory>::unpack(mem,localEpsInvPow,ps);
Unpacker<decltype(calcKernels),HeapMemory>::unpack(mem,calcKernels,ps);
Unpacker<decltype(kerOffsets),HeapMemory>::unpack(mem,kerOffsets,ps);
return;
}
void checkMomenta(vector_type &particles)
{
openfpm::vector<aggregate<double,double>> momenta;
openfpm::vector<aggregate<double,double>> momenta_accu;
momenta.resize(monomialBasis.size());
momenta_accu.resize(monomialBasis.size());
for (int i = 0 ; i < momenta.size() ; i++)
{
momenta.template get<0>(i) = 3000000000.0;
momenta.template get<1>(i) = -3000000000.0;
}
auto it = particles.getDomainIterator();
auto supportsIt = localSupports.begin();
auto epsIt = localEps.begin();
while (it.isNext())
{
double eps = *epsIt;
for (int i = 0 ; i < momenta.size() ; i++)
{
momenta_accu.template get<0>(i) = 0.0;
}
Support support = *supportsIt;
size_t xpK = support.getReferencePointKey();
Point<dim, T> xp = particles.getPos(support.getReferencePointKey());
size_t kerOff = kerOffsets.get(xpK);
auto & keys = support.getKeys();
for (int i = 0 ; i < keys.size() ; i++)
{
size_t xqK = keys.get(i);
Point<dim, T> xq = particles.getPosOrig(xqK);
Point<dim, T> normalizedArg = (xp - xq) / eps;
auto ker = calcKernels.get(kerOff+i);
int counter = 0;
size_t N = monomialBasis.getElements().size();
for (size_t i = 0; i < N; ++i)
{
const Monomial<dim> &m = monomialBasis.getElement(i);
T mbValue = m.evaluate(normalizedArg);
momenta_accu.template get<0>(counter) += mbValue * ker;
++counter;
}
}
for (int i = 0 ; i < momenta.size() ; i++)
{
if (momenta_accu.template get<0>(i) < momenta.template get<0>(i))
{
momenta.template get<0>(i) = momenta_accu.template get<0>(i);
}
if (momenta_accu.template get<1>(i) > momenta.template get<1>(i))
{
momenta.template get<1>(i) = momenta_accu.template get<0>(i);
}
}
//
++it;
++supportsIt;
++epsIt;
}
for (size_t i = 0 ; i < momenta.size() ; i++)
{
std::cout << "MOMENTA: " << monomialBasis.getElement(i) << "Min: " << momenta.template get<0>(i) << " " << "Max: " << momenta.template get<1>(i) << std::endl;
}
}
/**
* Computes the value of the differential operator on all the particles,
* using the f values stored at the fValuePos position in the aggregate
* and storing the resulting Df values at the DfValuePos position in the aggregate.
* @tparam fValuePos Position in the aggregate of the f values to use.
* @tparam DfValuePos Position in the aggregate of the Df values to store.
* @param particles The set of particles to iterate over.
*/
template<unsigned int fValuePos, unsigned int DfValuePos>
void computeDifferentialOperator(vector_type &particles) {
char sign = 1;
if (differentialOrder % 2 == 0) {
sign = -1;
}
auto it = particles.getDomainIterator();
auto supportsIt = localSupports.begin();
auto epsItInvPow = localEpsInvPow.begin();
while (it.isNext()) {
double epsInvPow = *epsItInvPow;
T Dfxp = 0;
Support support = *supportsIt;
size_t xpK = support.getReferencePointKey();
//Point<dim, typename vector_type::stype> xp = particles.getPos(support.getReferencePointKey());
T fxp = sign * particles.template getProp<fValuePos>(xpK);
size_t kerOff = kerOffsets.get(xpK);
auto & keys = support.getKeys();
for (int i = 0 ; i < keys.size() ; i++)
{
size_t xqK = keys.get(i);
T fxq = particles.template getProp<fValuePos>(xqK);
Dfxp += (fxq + fxp) * calcKernels.get(kerOff+i);
}
Dfxp *= epsInvPow;
//
//T trueDfxp = particles.template getProp<2>(xpK);
// Store Dfxp in the right position
particles.template getProp<DfValuePos>(xpK) = Dfxp;
//
++it;
++supportsIt;
++epsItInvPow;
}
}
/*! \brief Get the number of neighbours
*
* \return the number of neighbours
*
*/
inline int getNumNN(const vect_dist_key_dx &key)
{
return localSupports.get(key.getKey()).size();
}
/*! \brief Get the coefficent j (Neighbour) of the particle key
*
* \param key particle
* \param j neighbour
*
* \return the coefficent
*
*/
inline T getCoeffNN(const vect_dist_key_dx &key, int j)
{
size_t base = kerOffsets.get(key.getKey());
return calcKernels.get(base + j);
}
/*! \brief Get the number of neighbours
*
* \return the number of neighbours
*
*/
inline size_t getIndexNN(const vect_dist_key_dx &key, int j)
{
return localSupports.get(key.getKey()).getKeys().get(j);
}
inline T getSign()
{
T sign = 1.0;
if (differentialOrder % 2 == 0 && differentialOrder!=0) {
sign = -1;
}
return sign;
}
T getEpsilonInvPrefactor(const vect_dist_key_dx &key)
{
return localEpsInvPow.get(key.getKey());
}
/**
* Computes the value of the differential operator for one particle for o1 representing a scalar
*
* \param key particle
* \param o1 source property
* \return the selected derivative
*
*/
template<typename op_type>
auto computeDifferentialOperator(const vect_dist_key_dx &key,
op_type &o1) -> decltype(is_scalar<std::is_fundamental<decltype(o1.value(
key))>::value>::analyze(key, o1)) {
typedef decltype(is_scalar<std::is_fundamental<decltype(o1.value(key))>::value>::analyze(key, o1)) expr_type;
T sign = 1.0;
if (differentialOrder % 2 == 0) {
sign = -1;
}
double eps = localEps.get(key.getKey());
double epsInvPow = localEpsInvPow.get(key.getKey());
auto &particles = o1.getVector();
#ifdef SE_CLASS1
if(particles.getMapCtr()!=this->getUpdateCtr())
{
std::cerr<<__FILE__<<":"<<__LINE__<<" Error: You forgot a DCPSE operator update after map."<<std::endl;
}
#endif
expr_type Dfxp = 0;
Support support = localSupports.get(key.getKey());
size_t xpK = support.getReferencePointKey();
//Point<dim, T> xp = particles.getPos(xpK);
expr_type fxp = sign * o1.value(key);
size_t kerOff = kerOffsets.get(xpK);
auto & keys = support.getKeys();
for (int i = 0 ; i < keys.size() ; i++)
{
size_t xqK = keys.get(i);
expr_type fxq = o1.value(vect_dist_key_dx(xqK));
Dfxp = Dfxp + (fxq + fxp) * calcKernels.get(kerOff+i);
}
Dfxp = Dfxp * epsInvPow;
//
//T trueDfxp = particles.template getProp<2>(xpK);
// Store Dfxp in the right position
return Dfxp;
}
/**
* Computes the value of the differential operator for one particle for o1 representing a vector
*
* \param key particle
* \param o1 source property
* \param i component
* \return the selected derivative
*
*/
template<typename op_type>
auto computeDifferentialOperator(const vect_dist_key_dx &key,
op_type &o1,
int i) -> typename decltype(is_scalar<std::is_fundamental<decltype(o1.value(
key))>::value>::analyze(key, o1))::coord_type {
typedef typename decltype(is_scalar<std::is_fundamental<decltype(o1.value(key))>::value>::analyze(key, o1))::coord_type expr_type;
//typedef typename decltype(o1.value(key))::blabla blabla;
T sign = 1.0;
if (differentialOrder % 2 == 0) {
sign = -1;
}
double eps = localEps.get(key.getKey());
double epsInvPow = localEpsInvPow.get(key.getKey());
auto &particles = o1.getVector();
#ifdef SE_CLASS1
if(particles.getMapCtr()!=this->getUpdateCtr())
{
std::cerr<<__FILE__<<":"<<__LINE__<<" Error: You forgot a DCPSE operator update after map."<<std::endl;
}
#endif
expr_type Dfxp = 0;
Support support = localSupports.get(key.getKey());
size_t xpK = support.getReferencePointKey();
//Point<dim, T> xp = particles.getPos(xpK);
expr_type fxp = sign * o1.value(key)[i];
size_t kerOff = kerOffsets.get(xpK);
auto & keys = support.getKeys();
for (int j = 0 ; j < keys.size() ; j++)
{
size_t xqK = keys.get(j);
expr_type fxq = o1.value(vect_dist_key_dx(xqK))[i];
Dfxp = Dfxp + (fxq + fxp) * calcKernels.get(kerOff+j);
}
Dfxp = Dfxp * epsInvPow;
//
//T trueDfxp = particles.template getProp<2>(xpK);
// Store Dfxp in the right position
return Dfxp;
}
void initializeUpdate(vector_type &particlesFrom,vector_type2 &particlesTo)
{
#ifdef SE_CLASS1
update_ctr=particlesFrom.getMapCtr();
#endif
localSupports.clear();
localEps.clear();
localEpsInvPow.clear();
calcKernels.clear();
kerOffsets.clear();
initializeStaticSize(particlesFrom,particlesTo, convergenceOrder, rCut, supportSizeFactor);
}
void initializeUpdate(vector_type &particles)
{
#ifdef SE_CLASS1
update_ctr=particles.getMapCtr();
#endif
localSupports.clear();
localEps.clear();
localEpsInvPow.clear();
calcKernels.clear();
kerOffsets.clear();
initializeStaticSize(particles,particles, convergenceOrder, rCut, supportSizeFactor);
}
protected:
void initializeStaticSize(vector_type &particlesFrom,vector_type2 &particlesTo,
unsigned int convergenceOrder,
T rCut,
T supportSizeFactor, T adaptiveSizeFactor = 1.0) {
#ifdef SE_CLASS1
this->update_ctr=particlesFrom.getMapCtr();
#endif
this->rCut=rCut;
this->supportSizeFactor=supportSizeFactor;
this->convergenceOrder=convergenceOrder;
auto & v_cl=create_vcluster();
if(this->opt==LOAD){
if(v_cl.rank()==0)
{std::cout<<"Warning: Creating empty DC-PSE operator! Please use update or load to get kernels."<<std::endl;}
return;
}
SupportBuilder<vector_type,vector_type2>
supportBuilder(particlesFrom,particlesTo, differentialSignature, rCut, differentialOrder == 0);
unsigned int requiredSupportSize = monomialBasis.size() * supportSizeFactor;
supportBuilder.setAdapFac(adaptiveSizeFactor);
if (!isSharedLocalSupport)
localSupports.resize(particlesTo.size_local_orig());
localEps.resize(particlesTo.size_local_orig());
localEpsInvPow.resize(particlesTo.size_local_orig());
kerOffsets.resize(particlesTo.size_local_orig());
kerOffsets.fill(-1);
T avgSpacingGlobal=0,avgSpacingGlobal2=0,maxSpacingGlobal=0,minSpacingGlobal=std::numeric_limits<T>::max();
size_t Counter=0;
auto it = particlesTo.getDomainIterator();
while (it.isNext()) {
// Get the points in the support of the DCPSE kernel and store the support for reuse
auto key_o = particlesTo.getOriginKey(it.get());
if (!isSharedLocalSupport)
localSupports.get(key_o.getKey()) = supportBuilder.getSupport(it, requiredSupportSize,opt);
Support& support = localSupports.get(key_o.getKey());
EMatrix<T, Eigen::Dynamic, Eigen::Dynamic> V(support.size(), monomialBasis.size());
// Vandermonde matrix computation
Vandermonde<dim, T, EMatrix<T, Eigen::Dynamic, Eigen::Dynamic>>
vandermonde(support, monomialBasis,particlesFrom,particlesTo,HOverEpsilon);
vandermonde.getMatrix(V);
T eps = vandermonde.getEps();
avgSpacingGlobal+=eps;
T tSpacing = vandermonde.getMinSpacing();
avgSpacingGlobal2+=tSpacing;
if(tSpacing>maxSpacingGlobal)
{
maxSpacingGlobal=tSpacing;
}
if(tSpacing<minSpacingGlobal)
{
minSpacingGlobal=tSpacing;
}
localEps.get(key_o.getKey()) = eps;
localEpsInvPow.get(key_o.getKey()) = 1.0 / openfpm::math::intpowlog(eps,differentialOrder);
// Compute the diagonal matrix E
DcpseDiagonalScalingMatrix<dim> diagonalScalingMatrix(monomialBasis);
EMatrix<T, Eigen::Dynamic, Eigen::Dynamic> E(support.size(), support.size());
diagonalScalingMatrix.buildMatrix(E, support, eps, particlesFrom, particlesTo);
// Compute intermediate matrix B
EMatrix<T, Eigen::Dynamic, Eigen::Dynamic> B = E * V;
// Compute matrix A
EMatrix<T, Eigen::Dynamic, Eigen::Dynamic> A = B.transpose() * B;
// Compute RHS vector b
DcpseRhs<dim> rhs(monomialBasis, differentialSignature);
EMatrix<T, Eigen::Dynamic, 1> b(monomialBasis.size(), 1);
rhs.template getVector<T>(b);
// Get the vector where to store the coefficients...
EMatrix<T, Eigen::Dynamic, 1> a(monomialBasis.size(), 1);
// ...solve the linear system...
a = A.colPivHouseholderQr().solve(b);
// ...and store the solution for later reuse
kerOffsets.get(key_o.getKey()) = calcKernels.size();
Point<dim, T> xp = particlesTo.getPosOrig(key_o);
const auto& support_keys = support.getKeys();
size_t N = support_keys.size();
for (size_t i = 0; i < N; ++i)
{
const auto& xqK = support_keys.get(i);
Point<dim, T> xq = particlesFrom.getPosOrig(xqK);
Point<dim, T> normalizedArg = (xp - xq) / eps;
calcKernels.add(computeKernel(normalizedArg, a));
}
//
++it;
++Counter;
}
v_cl.sum(avgSpacingGlobal);
v_cl.sum(avgSpacingGlobal2);
v_cl.max(maxSpacingGlobal);
v_cl.min(minSpacingGlobal);
v_cl.sum(Counter);
v_cl.execute();
if(v_cl.rank()==0)
{std::cout<<"DCPSE Operator Construction Complete. The global avg spacing in the support <h> is: "<<HOverEpsilon*avgSpacingGlobal/(T(Counter))<<" (c="<<HOverEpsilon<<"). Avg:"<<avgSpacingGlobal2/(T(Counter))<<" Range:["<<minSpacingGlobal<<","<<maxSpacingGlobal<<"]."<<std::endl;}
}
T computeKernel(Point<dim, T> x, EMatrix<T, Eigen::Dynamic, 1> & a) const {
T res = 0;
unsigned int counter = 0;
T expFactor = exp(-norm2(x));
size_t N = monomialBasis.getElements().size();
for (size_t i = 0; i < N; ++i)
{
const Monomial<dim> &m = monomialBasis.getElement(i);
T coeff = a(counter);
T mbValue = m.evaluate(x);
res += coeff * mbValue * expFactor;
++counter;
}
return res;
}
T conditionNumber(const EMatrix<T, -1, -1> &V, T condTOL) const {
Eigen::JacobiSVD<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>> svd(V);
T cond = svd.singularValues()(0)
/ svd.singularValues()(svd.singularValues().size() - 1);
if (cond > condTOL) {
std::cout
<< "WARNING: cond(V) = " << cond
<< " is greater than TOL = " << condTOL
<< ", numPoints(V) = " << V.rows()
<< std::endl; // debug
}
return cond;
}
};
template<unsigned int dim, typename vector_type,typename vector_type2=vector_type>
class SurfaceDcpse : Dcpse<dim, vector_type, vector_type2> {
public:
typedef typename vector_type::stype T;
protected:
openfpm::vector<size_t> accKerOffsets;
openfpm::vector<T> accCalcKernels;
openfpm::vector<T> nSpacings;
double nSpacing, adaptiveSizeFactor;
unsigned int nCount;
bool isSurfaceDerivative=false;
size_t initialParticleSize;
template<unsigned int NORMAL_ID>
void createNormalParticles(vector_type &particles)
{
particles.template ghost_get<NORMAL_ID>(SKIP_LABELLING);
initialParticleSize=particles.size_local_with_ghost();
auto it = particles.getDomainAndGhostIterator();
while(it.isNext()){
auto key=it.get();
Point<dim,T> xp=particles.getPos(key), Normals=particles.template getProp<NORMAL_ID>(key);
if(this->opt==support_options::ADAPTIVE)
nSpacing=nSpacings.get(key.getKey());
for(int i=1;i<=nCount;i++){
particles.appendLocal();
for(size_t j=0;j<dim;j++)
particles.getLastPosEnd()[j]=xp[j]+i*nSpacing*Normals[j];
particles.appendLocal();
for(size_t j=0;j<dim;j++)
particles.getLastPosEnd()[j]=xp[j]-i*nSpacing*Normals[j];
}
++it;
}
}
void accumulateAndDeleteNormalParticles(vector_type &particles)
{
accCalcKernels.clear();
accKerOffsets.clear();
accKerOffsets.resize(initialParticleSize);
accKerOffsets.fill(-1);
auto supportsIt = this->localSupports.begin();
tsl::hopscotch_map<size_t, size_t> nMap;
openfpm::vector_std<size_t> supportBuffer;
auto it = particles.getDomainIterator();
while(it.isNext()){
supportBuffer.clear();
nMap.clear();
auto key=it.get();
Support support = *supportsIt;
size_t xpK = support.getReferencePointKey();
size_t kerOff = this->kerOffsets.get(xpK);
accKerOffsets.get(xpK)=accCalcKernels.size();
auto &keys = support.getKeys();
for (int i = 0 ; i < keys.size() ; i++)
{
size_t xqK = keys.get(i);
int difference = static_cast<int>(xqK) - static_cast<int>(initialParticleSize);
int real_particle;
if (std::signbit(difference))
real_particle = xqK;
else
real_particle = difference / (2 * nCount);
auto found=nMap.find(real_particle);
if (found != nMap.end())
accCalcKernels.get(found->second) += this->calcKernels.get(kerOff+i);
else
{
supportBuffer.add();
supportBuffer.get(supportBuffer.size()-1) = real_particle;
accCalcKernels.add();
accCalcKernels.get(accCalcKernels.size()-1) = this->calcKernels.get(kerOff+i);
nMap[real_particle]=accCalcKernels.size()-1;
}
}
keys.swap(supportBuffer);
this->localSupports.get(xpK) = support;
++supportsIt;
++it;
}
particles.discardLocalAppend(initialParticleSize);
this->localEps.resize(initialParticleSize);
this->localEpsInvPow.resize(initialParticleSize);
this->localSupports.resize(initialParticleSize);
this->calcKernels.swap(accCalcKernels);
this->kerOffsets.swap(accKerOffsets);
}
public:
//Surface DCPSE Constructor
template<unsigned int NORMAL_ID>
SurfaceDcpse(
vector_type &particles,
Point<dim, unsigned int> differentialSignature,
unsigned int convergenceOrder,
T rCut,
T nSpacing,
value_t< NORMAL_ID >,
support_options opt = support_options::RADIUS)
:
Dcpse<dim, vector_type, vector_type2>(particles, differentialSignature, convergenceOrder, opt),
isSurfaceDerivative(true),
nSpacing(nSpacing),
nCount(floor(rCut/nSpacing))
{
particles.ghost_get_subset(); // This communicates which ghost particles to be excluded from support
if(opt==support_options::ADAPTIVE) {
adaptiveSizeFactor=nSpacing;
if (dim==2) nCount=3;
else nCount=2;
SupportBuilder<vector_type,vector_type2> supportBuilder(
particles,
particles,
this->differentialSignature,
this->rCut,
this->differentialOrder == 0
);
supportBuilder.setAdapFac(nSpacing);
auto it = particles.getDomainAndGhostIterator();
while (it.isNext()) {
auto key_o = particles.getOriginKey(it.get());
Support support = supportBuilder.getSupport(it, this->monomialBasis.size(), this->opt);
nSpacings.add(supportBuilder.getLastMinspacing());
++it;
}
}
if(opt!=support_options::LOAD) {
createNormalParticles<NORMAL_ID>(particles);
#ifdef SE_CLASS1
particles.write("WithNormalParticlesQC");
#endif
}
this->initializeStaticSize(
particles,
particles,
convergenceOrder,
rCut,
this->supportSizeFactor,
adaptiveSizeFactor
);
if(opt!=support_options::LOAD) {
accumulateAndDeleteNormalParticles(particles);
}
}
};
#endif
#endif //OPENFPM_PDATA_DCPSE_HPP