5#ifndef OPENFPM_PDATA_DCPSE_HPP
6#define OPENFPM_PDATA_DCPSE_HPP
10#include "Vector/vector_dist.hpp"
11#include "MonomialBasis.hpp"
12#include "DMatrix/EMatrix.hpp"
13#include "SupportBuilder.hpp"
15#include "Vandermonde.hpp"
16#include "DcpseDiagonalScalingMatrix.hpp"
17#include "DcpseRhs.hpp"
18#include "hash_map/hopscotch_map.h"
20template<
unsigned int N>
struct value_t {};
24 template<
typename op_type>
26 analyze(
const vect_dist_key_dx &key, op_type &o1) ->
typename std::remove_reference<
decltype(o1.value(
33struct is_scalar<false> {
34 template<
typename op_type>
36 analyze(
const vect_dist_key_dx &key, op_type &o1) ->
typename std::remove_reference<
decltype(o1.value(
42template<
unsigned int dim,
typename vector_type,
typename vector_type2=vector_type>
46 typedef typename vector_type::stype T;
61 double HOverEpsilon=0.9;
64 const unsigned int differentialOrder;
67 bool isSharedLocalSupport =
false;
78 double rCut,supportSizeFactor=1,nSpacing,AdapFac;
79 unsigned int convergenceOrder,nCount;
81 bool isSurfaceDerivative=
false;
82 size_t initialParticleSize;
87 template<
unsigned int NORMAL_ID>
90 particles.template ghost_get<NORMAL_ID>(SKIP_LABELLING);
96 if(opt==support_options::ADAPTIVE)
98 nSpacing=nSpacings.get(key.getKey());
100 for(
int i=1;i<=nCount;i++){
102 for(
size_t j=0;j<dim;j++)
105 for(
size_t j=0;j<dim;j++)
116 auto supportsIt = localSupports.begin();
118 accCalcKernels.clear();
119 accKerOffsets.clear();
120 accKerOffsets.resize(initialParticleSize);
121 accKerOffsets.fill(-1);
123 supportBuffer.clear();
127 size_t xpK = support.getReferencePointKey();
128 size_t kerOff = kerOffsets.get(xpK);
129 auto &keys = support.getKeys();
130 accKerOffsets.get(xpK)=accCalcKernels.
size();
131 for (
int i = 0 ; i < keys.size() ; i++)
133 size_t xqK = keys.get(i);
134 int real_particle=(xqK-initialParticleSize)/(2.*nCount);
139 auto found=nMap.find(real_particle);
140 if(found!=nMap.end()){
141 accCalcKernels.get(found->second)+=calcKernels.get(kerOff+i);
145 supportBuffer.get(supportBuffer.
size()-1)=real_particle;
146 accCalcKernels.add();
147 accCalcKernels.get(accCalcKernels.
size()-1)=calcKernels.get(kerOff+i);
148 nMap[real_particle]=accCalcKernels.
size()-1;
151 keys.swap(supportBuffer);
152 localSupports.get(xpK) = support;
157 localEps.resize(initialParticleSize);
158 localEpsInvPow.resize(initialParticleSize);
159 localSupports.resize(initialParticleSize);
160 calcKernels.swap(accCalcKernels);
161 kerOffsets.swap(accKerOffsets);
165 int getUpdateCtr()
const
175 unsigned int convergenceOrder,
177 T supportSizeFactor = 1,
178 support_options opt = support_options::RADIUS)
181 differentialSignature(differentialSignature),
182 differentialOrder(
Monomial<dim>(differentialSignature).order()),
183 monomialBasis(differentialSignature.asArray(), convergenceOrder),
187 initializeStaticSize(
particles,
particles, convergenceOrder, rCut, supportSizeFactor);
191 template<
unsigned int NORMAL_ID>
194 unsigned int convergenceOrder,
197 value_t< NORMAL_ID >,
198 support_options opt = support_options::RADIUS)
201 differentialSignature(differentialSignature),
202 differentialOrder(
Monomial<dim>(differentialSignature).order()),
203 monomialBasis(differentialSignature.asArray(), convergenceOrder),
204 opt(opt),isSurfaceDerivative(true),nSpacing(nSpacing),nCount(floor(rCut/nSpacing))
208 if(opt==support_options::ADAPTIVE) {
209 this->AdapFac=nSpacing;
217 supportBuilder(particlesFrom,particlesTo, differentialSignature, rCut, differentialOrder == 0);
218 supportBuilder.setAdapFac(nSpacing);
219 auto it = particlesTo.getDomainAndGhostIterator();
220 while (it.isNext()) {
221 auto key_o = particlesTo.getOriginKey(it.get());
222 Support support = supportBuilder.getSupport(it,monomialBasis.size(),opt);
223 nSpacings.add(supportBuilder.getLastMinspacing());
228 if(opt!=support_options::LOAD) {
229 createNormalParticles<NORMAL_ID>(
particles);
234 initializeStaticSize(
particles,
particles, convergenceOrder, rCut, supportSizeFactor);
235 if(opt!=support_options::LOAD) {
236 accumulateAndDeleteNormalParticles(
particles);
241 const Dcpse<dim, vector_type>& other,
243 unsigned int convergenceOrder,
245 T supportSizeFactor = 1,
246 support_options opt = support_options::RADIUS)
248 differentialSignature(differentialSignature),
249 differentialOrder(
Monomial<dim>(differentialSignature).order()),
250 monomialBasis(differentialSignature.asArray(), convergenceOrder),
251 localSupports(other.localSupports),
252 isSharedLocalSupport(true)
255 initializeStaticSize(
particles,
particles, convergenceOrder, rCut, supportSizeFactor);
260 unsigned int convergenceOrder,
262 T supportSizeFactor = 1,
263 support_options opt = support_options::RADIUS)
264 :particlesFrom(particlesFrom),particlesTo(particlesTo),
265 differentialSignature(differentialSignature),
266 differentialOrder(
Monomial<dim>(differentialSignature).order()),
267 monomialBasis(differentialSignature.asArray(), convergenceOrder),
271 initializeStaticSize(particlesFrom,particlesTo,convergenceOrder, rCut, supportSizeFactor);
275 template<
unsigned int prp>
278 Support support = localSupports.get(k);
280 size_t kerOff = kerOffsets.get(k);
281 auto & keys = support.getKeys();
282 for (
int i = 0 ; i < keys.size() ; i++)
284 size_t xqK = keys.get(i);
285 particles.template getProp<prp>(xqK) += calcKernels.get(kerOff+i);
289 template<
unsigned int prp>
292 Support support = localSupports.get(k);
294 size_t kerOff = kerOffsets.get(k);
295 auto & keys = support.getKeys();
296 for (
int i = 0 ; i < keys.size() ; i++)
298 size_t xqK = keys.get(i);
299 particles.template getProp<prp>(xqK) = 1.0;
303 template<
unsigned int prp>
307 Support support = localSupports.get(k);
309 size_t kerOff = kerOffsets.get(k);
310 auto & keys = support.getKeys();
311 for (
int i = 0 ; i < keys.size() ; i++)
313 size_t xqK = keys.get(i);
314 particles.template getProp<prp>(xqK)[i] += calcKernels.get(kerOff+i);
320 template<
unsigned int prp1,
unsigned int prp2>
323 typedef typename std::remove_reference<
decltype(particlesTo.template getProp<prp2>(0))>::type T2;
326 auto supportsIt = localSupports.begin();
327 auto epsItInvPow = localEpsInvPow.begin();
329 double epsInvPow = *epsItInvPow;
332 size_t xpK = support.getReferencePointKey();
335 size_t kerOff = kerOffsets.get(xpK);
336 auto & keys = support.getKeys();
337 for (
int i = 0 ; i < keys.size() ; i++)
339 size_t xqK = keys.get(i);
340 T2 fxq = particlesFrom.template getProp<prp1>(xqK);
341 Dfxp += fxq * calcKernels.get(kerOff+i);
343 Dfxp = epsInvPow*Dfxp;
347 particlesTo.template getProp<prp2>(xpK) = Dfxp;
357 void save(
const std::string &file){
358 auto & v_cl=create_vcluster();
363 Packer<
decltype(localEpsInvPow),
HeapMemory>::packRequest(localEpsInvPow,req);
381 std::ofstream dump (file+
"_"+std::to_string(v_cl.rank()), std::ios::out | std::ios::binary);
382 if (dump.is_open() ==
false)
383 { std::cerr << __FILE__ <<
":" << __LINE__ <<
" Unable to write since dump is open at rank "<<v_cl.rank()<<std::endl;
393 void load(
const std::string & file)
395 auto & v_cl=create_vcluster();
396 std::ifstream fs (file+
"_"+std::to_string(v_cl.rank()), std::ios::in | std::ios::binary | std::ios::ate );
397 if (fs.is_open() ==
false)
399 std::cerr << __FILE__ <<
":" << __LINE__ <<
" error, opening file: " << file << std::endl;
404 size_t sz = fs.tellg();
409 std::ifstream input (file+
"_"+std::to_string(v_cl.rank()), std::ios::in | std::ios::binary );
410 if (input.is_open() ==
false)
420 mem.allocate(pmem.
size());
444 momenta.resize(monomialBasis.size());
445 momenta_accu.resize(monomialBasis.size());
447 for (
int i = 0 ; i < momenta.
size() ; i++)
449 momenta.template get<0>(i) = 3000000000.0;
450 momenta.template get<1>(i) = -3000000000.0;
454 auto supportsIt = localSupports.begin();
455 auto epsIt = localEps.begin();
460 for (
int i = 0 ; i < momenta.
size() ; i++)
462 momenta_accu.template get<0>(i) = 0.0;
466 size_t xpK = support.getReferencePointKey();
468 size_t kerOff = kerOffsets.get(xpK);
469 auto & keys = support.getKeys();
470 for (
int i = 0 ; i < keys.size() ; i++)
472 size_t xqK = keys.get(i);
476 auto ker = calcKernels.get(kerOff+i);
479 size_t N = monomialBasis.getElements().size();
481 for (
size_t i = 0; i < N; ++i)
485 T mbValue = m.evaluate(normalizedArg);
486 momenta_accu.template get<0>(counter) += mbValue * ker;
492 for (
int i = 0 ; i < momenta.
size() ; i++)
494 if (momenta_accu.template get<0>(i) < momenta.template get<0>(i))
496 momenta.template get<0>(i) = momenta_accu.template get<0>(i);
499 if (momenta_accu.template get<1>(i) > momenta.template get<1>(i))
501 momenta.template get<1>(i) = momenta_accu.template get<0>(i);
511 for (
size_t i = 0 ; i < momenta.
size() ; i++)
513 std::cout <<
"MOMENTA: " << monomialBasis.getElement(i) <<
"Min: " << momenta.template get<0>(i) <<
" " <<
"Max: " << momenta.template get<1>(i) << std::endl;
525 template<
unsigned int fValuePos,
unsigned int DfValuePos>
528 if (differentialOrder % 2 == 0) {
533 auto supportsIt = localSupports.begin();
534 auto epsItInvPow = localEpsInvPow.begin();
535 while (it.isNext()) {
536 double epsInvPow = *epsItInvPow;
540 size_t xpK = support.getReferencePointKey();
542 T fxp = sign *
particles.template getProp<fValuePos>(xpK);
543 size_t kerOff = kerOffsets.get(xpK);
544 auto & keys = support.getKeys();
545 for (
int i = 0 ; i < keys.size() ; i++)
547 size_t xqK = keys.get(i);
548 T fxq =
particles.template getProp<fValuePos>(xqK);
550 Dfxp += (fxq + fxp) * calcKernels.get(kerOff+i);
556 particles.template getProp<DfValuePos>(xpK) = Dfxp;
572 return localSupports.get(key.
getKey()).
size();
585 size_t base = kerOffsets.get(key.
getKey());
586 return calcKernels.get(base + j);
596 return localSupports.get(key.
getKey()).getKeys().get(j);
603 if (differentialOrder % 2 == 0 && differentialOrder!=0) {
612 return localEpsInvPow.get(key.
getKey());
623 template<
typename op_type>
625 op_type &o1) ->
decltype(is_scalar<std::is_fundamental<
decltype(o1.value(
626 key))>::value>::analyze(key, o1)) {
628 typedef decltype(is_scalar<std::is_fundamental<
decltype(o1.value(key))>::value>::analyze(key, o1)) expr_type;
631 if (differentialOrder % 2 == 0) {
635 double eps = localEps.get(key.
getKey());
636 double epsInvPow = localEpsInvPow.get(key.
getKey());
641 if(
particles.getMapCtr()!=this->getUpdateCtr())
643 std::cerr<<__FILE__<<
":"<<__LINE__<<
" Error: You forgot a DCPSE operator update after map."<<std::endl;
649 size_t xpK = support.getReferencePointKey();
651 expr_type fxp = sign * o1.value(key);
652 size_t kerOff = kerOffsets.get(xpK);
653 auto & keys = support.getKeys();
654 for (
int i = 0 ; i < keys.size() ; i++)
656 size_t xqK = keys.get(i);
658 Dfxp = Dfxp + (fxq + fxp) * calcKernels.get(kerOff+i);
660 Dfxp = Dfxp * epsInvPow;
676 template<
typename op_type>
679 int i) ->
typename decltype(is_scalar<std::is_fundamental<
decltype(o1.value(
680 key))>::value>::analyze(key, o1))::coord_type {
682 typedef typename decltype(is_scalar<std::is_fundamental<
decltype(o1.value(key))>::value>::analyze(key, o1))::coord_type expr_type;
687 if (differentialOrder % 2 == 0) {
691 double eps = localEps.get(key.
getKey());
692 double epsInvPow = localEpsInvPow.get(key.
getKey());
696 if(
particles.getMapCtr()!=this->getUpdateCtr())
698 std::cerr<<__FILE__<<
":"<<__LINE__<<
" Error: You forgot a DCPSE operator update after map."<<std::endl;
704 size_t xpK = support.getReferencePointKey();
706 expr_type fxp = sign * o1.value(key)[i];
707 size_t kerOff = kerOffsets.get(xpK);
708 auto & keys = support.getKeys();
709 for (
int j = 0 ; j < keys.size() ; j++)
711 size_t xqK = keys.get(j);
713 Dfxp = Dfxp + (fxq + fxp) * calcKernels.get(kerOff+j);
715 Dfxp = Dfxp * epsInvPow;
726 update_ctr=particlesFrom.getMapCtr();
729 localSupports.clear();
731 localEpsInvPow.clear();
734 initializeStaticSize(particlesFrom,particlesTo, convergenceOrder, rCut, supportSizeFactor);
743 localSupports.clear();
745 localEpsInvPow.clear();
754 unsigned int convergenceOrder,
756 T supportSizeFactor) {
758 this->update_ctr=particlesFrom.getMapCtr();
761 this->supportSizeFactor=supportSizeFactor;
762 this->convergenceOrder=convergenceOrder;
763 auto & v_cl=create_vcluster();
766 {std::cout<<
"Warning: Creating empty DC-PSE operator! Please use update or load to get kernels."<<std::endl;}
770 supportBuilder(particlesFrom,particlesTo, differentialSignature, rCut, differentialOrder == 0);
771 unsigned int requiredSupportSize = monomialBasis.size() * supportSizeFactor;
772 supportBuilder.setAdapFac(AdapFac);
774 if (!isSharedLocalSupport)
780 T avgSpacingGlobal=0,avgSpacingGlobal2=0,maxSpacingGlobal=0,minSpacingGlobal=std::numeric_limits<T>::max();
783 while (it.isNext()) {
785 auto key_o = particlesTo.getOriginKey(it.get());
787 if (!isSharedLocalSupport)
788 localSupports.get(key_o.getKey()) = supportBuilder.getSupport(it, requiredSupportSize,opt);
790 Support& support = localSupports.get(key_o.getKey());
792 EMatrix<T, Eigen::Dynamic, Eigen::Dynamic> V(support.size(), monomialBasis.size());
796 vandermonde(support, monomialBasis,particlesFrom,particlesTo,HOverEpsilon);
797 vandermonde.getMatrix(V);
799 T eps = vandermonde.getEps();
800 avgSpacingGlobal+=eps;
801 T tSpacing = vandermonde.getMinSpacing();
802 avgSpacingGlobal2+=tSpacing;
803 if(tSpacing>maxSpacingGlobal)
805 maxSpacingGlobal=tSpacing;
807 if(tSpacing<minSpacingGlobal)
809 minSpacingGlobal=tSpacing;
812 localEps.get(key_o.getKey()) = eps;
813 localEpsInvPow.get(key_o.getKey()) = 1.0 / openfpm::math::intpowlog(eps,differentialOrder);
816 EMatrix<T, Eigen::Dynamic, Eigen::Dynamic> E(support.size(), support.size());
817 diagonalScalingMatrix.buildMatrix(E, support, eps, particlesFrom, particlesTo);
819 EMatrix<T, Eigen::Dynamic, Eigen::Dynamic> B = E * V;
821 EMatrix<T, Eigen::Dynamic, Eigen::Dynamic> A = B.transpose() * B;
825 EMatrix<T, Eigen::Dynamic, 1> b(monomialBasis.size(), 1);
826 rhs.template getVector<T>(b);
828 EMatrix<T, Eigen::Dynamic, 1> a(monomialBasis.size(), 1);
830 a = A.colPivHouseholderQr().solve(b);
832 kerOffsets.get(key_o.getKey()) = calcKernels.
size();
836 const auto& support_keys = support.getKeys();
837 size_t N = support_keys.size();
838 for (
size_t i = 0; i < N; ++i)
840 const auto& xqK = support_keys.get(i);
843 calcKernels.add(computeKernel(normalizedArg, a));
850 v_cl.sum(avgSpacingGlobal);
851 v_cl.sum(avgSpacingGlobal2);
852 v_cl.max(maxSpacingGlobal);
853 v_cl.min(minSpacingGlobal);
857 {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;}
860 T computeKernel(
Point<dim, T> x, EMatrix<T, Eigen::Dynamic, 1> & a)
const {
862 unsigned int counter = 0;
863 T expFactor = exp(-norm2(x));
865 size_t N = monomialBasis.getElements().size();
866 for (
size_t i = 0; i < N; ++i)
870 T coeff = a(counter);
871 T mbValue = m.evaluate(x);
872 res += coeff * mbValue * expFactor;
879 T conditionNumber(
const EMatrix<T, -1, -1> &V, T condTOL)
const {
880 Eigen::JacobiSVD<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>> svd(V);
881 T cond = svd.singularValues()(0)
882 / svd.singularValues()(svd.singularValues().size() - 1);
883 if (cond > condTOL) {
885 <<
"WARNING: cond(V) = " << cond
886 <<
" is greater than TOL = " << condTOL
887 <<
", numPoints(V) = " << V.rows()
This class allocate, and destroy CPU memory.
virtual void * getPointer()
get a readable pointer with the data
virtual size_t size() const
the the size of the allocated memory
This class implement the point shape in an N-dimensional space.
Implementation of 1-D std::vector like structure.
Grid key for a distributed grid.
__device__ __host__ size_t getKey() const
Get the key.
vect_dist_key_dx get()
Get the actual key.
auto getPosOrig(vect_dist_key_dx vec_key) -> decltype(vd.getPos(vec_key))
Get the position of an element.
vector_dist_iterator_subset getDomainIterator() const
Get an iterator that traverse the particles in the domain.
size_t size_local_orig() const
return the local size of the original vector
size_t size_local_with_ghost() const
return the local size of the vector
auto getPos(vect_dist_key_dx vec_key) -> decltype(v_pos.template get< 0 >(vec_key.getKey()))
Get the position of an element.
void addAtEnd()
Add at the END of local and ghost particle.
vector_dist_iterator getDomainIterator() const
Get an iterator that traverse the particles in the domain.
auto getLastPosEnd() -> decltype(v_pos.template get< 0 >(0))
Get the position of the last element after ghost.
bool write(std::string out, int opt=VTK_WRITER)
Output particle position and properties.
auto getPosOrig(vect_dist_key_dx vec_key) const -> decltype(v_pos.template get< 0 >(vec_key.getKey()))
Get the position of an element.
vector_dist_iterator getDomainAndGhostIterator() const
Get an iterator that traverse the particles in the domain.
void ghost_get_subset()
Stub does not do anything.
void resizeAtEnd(size_t rs)
Resize the vector at the end of the ghost (locally)
aggregate of properties, from a list of object if create a struct that follow the OPENFPM native stru...