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"
14 #include "Vandermonde.hpp"
15 #include "DcpseDiagonalScalingMatrix.hpp"
16 #include "DcpseRhs.hpp"
17 #include "hash_map/hopscotch_map.h"
18 #include <type_traits>
20 template<
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(
33 struct 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(
43 template<
unsigned int dim,
typename VerletList_type,
typename vector_type,
typename vector_type2=vector_type>
46 typedef typename vector_type::stype T;
56 const unsigned int differentialOrder;
64 VerletList_type & verletList;
68 unsigned int convergenceOrder;
83 int getUpdateCtr()
const
93 VerletList_type& verletList,
95 unsigned int convergenceOrder,
97 support_options opt = support_options::RADIUS
101 verletList(verletList),
102 differentialSignature(differentialSignature),
103 differentialOrder(
Monomial<dim>(differentialSignature).order()),
104 monomialBasis(differentialSignature.asArray(), convergenceOrder),
114 VerletList_type& verletList,
116 unsigned int convergenceOrder,
118 support_options opt = support_options::RADIUS
120 particlesSupport(particlesSupport),
121 particlesDomain(particlesDomain),
122 verletList(verletList),
123 differentialSignature(differentialSignature),
124 differentialOrder(
Monomial<dim>(differentialSignature).order()),
125 monomialBasis(differentialSignature.asArray(), convergenceOrder),
129 initializeStaticSize(particlesSupport,particlesDomain,convergenceOrder, rCut);
137 VerletList_type& verletList,
139 unsigned int convergenceOrder,
142 particlesSupport(particlesSupport),
143 particlesDomain(particlesDomain),
144 verletList(verletList),
145 differentialSignature(differentialSignature),
146 differentialOrder(
Monomial<dim>(differentialSignature).order()),
147 monomialBasis(differentialSignature.asArray(), convergenceOrder),
151 template<
unsigned int prp>
154 size_t kerOff = kerOffsets.get(p);
155 auto verletIt = this->verletList.getNNIterator(p);
157 while (verletIt.isNext())
159 size_t q = verletIt.get();
160 particles.template getProp<prp>(q) += calcKernels.get(kerOff+i);
165 template<
unsigned int prp>
168 size_t kerOff = kerOffsets.get(p);
169 auto verletIt = this->verletList.getNNIterator(p);
171 while (verletIt.isNext())
173 size_t q = verletIt.get();
175 particles.template getProp<prp>(q) = 1.0;
180 template<
unsigned int prp>
184 size_t kerOff = kerOffsets.get(p);
185 auto verletIt = this->verletList.getNNIterator(p);
187 while (verletIt.isNext())
189 size_t q = verletIt.get();
190 particles.template getProp<prp>(q)[index] += calcKernels.get(kerOff+i);
198 template<
unsigned int prp1,
unsigned int prp2>
201 typedef typename std::remove_reference<decltype(particlesDomain.template getProp<prp2>(0))>::type T2;
204 auto epsItInvPow = localEpsInvPow.begin();
206 T epsInvPow = *epsItInvPow;
210 auto verletIt = this->verletList.getNNIterator(p);
212 size_t kerOff = kerOffsets.get(p);
214 while (verletIt.isNext())
216 size_t q = verletIt.get();
217 T2 fxq = particlesSupport.template getProp<prp1>(q);
218 Dfxp += fxq * calcKernels.get(kerOff+i);
221 Dfxp = epsInvPow*Dfxp;
222 particlesDomain.template getProp<prp2>(p) = Dfxp;
238 template<
unsigned int prp1,
unsigned int prp2,
size_t N1>
241 typedef typename std::remove_reference<decltype(particlesDomain.template getProp<prp2>(0)[0])>::type T2;
248 auto epsItInvPow = localEpsInvPow.begin();
250 double epsInvPow = *epsItInvPow;
253 for (
size_t i1 = 0; i1 < N1; ++i1)
259 auto verletIt = this->verletList.getNNIterator(p);
262 size_t kerOff = kerOffsets.get(p);
265 while (verletIt.isNext())
267 size_t q = verletIt.get();
270 for (
size_t i1 = 0; i1 < N1; ++i1)
272 fxq[i1] = particlesSupport.template getProp<prp1>(q)[i1];
273 Dfxp[i1] += fxq[i1] * calcKernels.get(kerOff+i);
279 for (
size_t i1 = 0; i1 < N1; ++i1)
281 Dfxp[i1] = epsInvPow*Dfxp[i1];
288 for (
size_t i1 = 0; i1 < N1; ++i1)
290 particlesDomain.template getProp<prp2>(p)[i1] = Dfxp[i1];
302 void save(
const std::string &file){
303 auto & v_cl=create_vcluster();
307 Packer<decltype(localEpsInvPow),
HeapMemory>::packRequest(localEpsInvPow,req);
324 std::ofstream dump (file+
"_"+std::to_string(v_cl.rank()), std::ios::out | std::ios::binary);
325 if (dump.is_open() ==
false)
326 { std::cerr << __FILE__ <<
":" << __LINE__ <<
" Unable to write since dump is open at rank "<<v_cl.rank()<<std::endl;
337 void load(
const std::string & file)
339 auto & v_cl=create_vcluster();
340 std::ifstream fs (file+
"_"+std::to_string(v_cl.rank()), std::ios::in | std::ios::binary | std::ios::ate );
341 if (fs.is_open() ==
false)
343 std::cerr << __FILE__ <<
":" << __LINE__ <<
" error, opening file: " << file << std::endl;
348 size_t sz = fs.tellg();
353 std::ifstream input (file+
"_"+std::to_string(v_cl.rank()), std::ios::in | std::ios::binary );
354 if (input.is_open() ==
false)
364 mem.allocate(pmem.
size());
386 momenta.resize(monomialBasis.size());
387 momenta_accu.resize(monomialBasis.size());
389 for (
int i = 0 ; i < momenta.
size() ; i++)
391 momenta.template get<0>(i) = 3000000000.0;
392 momenta.template get<1>(i) = -3000000000.0;
396 auto epsIt = localEps.begin();
401 for (
int i = 0 ; i < momenta.
size() ; i++)
403 momenta_accu.template get<0>(i) = 0.0;
407 auto verletIt = this->verletList.getNNIterator(p);
410 size_t kerOff = kerOffsets.get(p);
412 while (verletIt.isNext())
414 size_t q = verletIt.get();
419 auto ker = calcKernels.get(kerOff+i);
422 size_t N = monomialBasis.getElements().size();
424 for (
size_t j = 0; j < N; ++j)
428 T mbValue = m.evaluate(normalizedArg);
429 momenta_accu.template get<0>(counter) += mbValue * ker;
436 for (
int i = 0 ; i < momenta.
size() ; i++)
438 if (momenta_accu.template get<0>(i) < momenta.template get<0>(i))
440 momenta.template get<0>(i) = momenta_accu.template get<0>(i);
443 if (momenta_accu.template get<1>(i) > momenta.template get<1>(i))
445 momenta.template get<1>(i) = momenta_accu.template get<0>(i);
453 for (
size_t i = 0 ; i < momenta.
size() ; i++)
455 std::cout <<
"MOMENTA: " << monomialBasis.getElement(i) <<
"Min: " << momenta.template get<0>(i) <<
" " <<
"Max: " << momenta.template get<1>(i) << std::endl;
467 template<
unsigned int fValuePos,
unsigned int DfValuePos>
470 if (differentialOrder % 2 == 0) {
475 auto epsItInvPow = localEpsInvPow.begin();
476 while (it.isNext()) {
477 T epsInvPow = *epsItInvPow;
481 auto verletIt = this->verletList.getNNIterator(p);
482 T fxp = sign *
particles.template getProp<fValuePos>(p);
483 size_t kerOff = kerOffsets.get(p);
485 while (verletIt.isNext())
487 size_t q = verletIt.get();
488 T fxq =
particles.template getProp<fValuePos>(q);
490 Dfxp += (fxq + fxp) * calcKernels.get(kerOff+i);
494 particles.template getProp<DfValuePos>(p) = Dfxp;
509 return verletList.getNNPart(p);
522 size_t base = kerOffsets.get(p.getKey());
523 return calcKernels.get(base + j);
533 return verletList.get(p, q);
540 if (differentialOrder % 2 == 0 && differentialOrder!=0) {
549 return localEpsInvPow.get(p.getKey());
560 template<
typename op_type>
562 op_type &o1) -> decltype(is_scalar<std::is_fundamental<decltype(o1.value(
563 p))>::value>::analyze(p, o1)) {
565 typedef decltype(is_scalar<std::is_fundamental<decltype(o1.value(p))>::value>::analyze(p, o1)) expr_type;
568 if (differentialOrder % 2 == 0) {
572 T eps = localEps.get(p.getKey());
573 T epsInvPow = localEpsInvPow.get(p.getKey());
578 if(
particles.getMapCtr()!=this->getUpdateCtr())
580 std::cerr<<__FILE__<<
":"<<__LINE__<<
" Error: You forgot a DCPSE operator update after map."<<std::endl;
585 auto verletIt = this->verletList.getNNIterator(p);
587 expr_type fxp = sign * o1.value(p);
588 size_t kerOff = kerOffsets.get(p);
591 while (verletIt.isNext())
593 size_t q = verletIt.get();
596 Dfxp = Dfxp + (fxq + fxp) * calcKernels.get(kerOff+i);
600 Dfxp = Dfxp * epsInvPow;
614 template<
typename op_type>
615 auto computeDifferentialOperator(
619 ) ->
typename decltype(is_scalar<std::is_fundamental<decltype(o1.value(p))>::value>::analyze(p, o1))::coord_type
621 typedef typename decltype(is_scalar<std::is_fundamental<decltype(o1.value(p))>::value>::analyze(p, o1))::coord_type expr_type;
624 if (differentialOrder % 2 == 0) {
628 T eps = localEps.get(p.getKey());
629 T epsInvPow = localEpsInvPow.get(p.getKey());
633 if(
particles.getMapCtr()!=this->getUpdateCtr())
635 std::cerr<<__FILE__<<
":"<<__LINE__<<
" Error: You forgot a DCPSE operator update after map."<<std::endl;
641 expr_type fxp = sign * o1.value(p)[i];
642 size_t kerOff = kerOffsets.get(p);
644 auto verletIt = this->verletList.getNNIterator(p);
647 while (verletIt.isNext())
649 size_t q = verletIt.get();
652 Dfxp = Dfxp + (fxq + fxp) * calcKernels.get(kerOff+j);
656 Dfxp = Dfxp * epsInvPow;
664 update_ctr=particlesSupport.getMapCtr();
668 localEpsInvPow.clear();
672 initializeStaticSize(particlesSupport, particlesDomain, convergenceOrder, rCut);
682 localEpsInvPow.clear();
690 void initializeStaticSize(
693 unsigned int convergenceOrder,
697 this->update_ctr=particlesSupport.getMapCtr();
700 this->convergenceOrder=convergenceOrder;
701 auto & v_cl=create_vcluster();
705 {std::cout<<
"Warning: Creating empty DC-PSE operator! Please use update or load to get kernels."<<std::endl;}
709 localEps.resize(particlesDomain.
size_local());
710 localEpsInvPow.resize(particlesDomain.
size_local());
711 kerOffsets.resize(particlesDomain.
size_local());
713 T avgSpacingGlobal=0,avgSpacingGlobal2=0,maxSpacingGlobal=0,minSpacingGlobal=std::numeric_limits<T>::max();
717 while (it.isNext()) {
721 auto verletIt = verletList.getNNIterator(p);
724 vandermonde(p, verletIt, monomialBasis,particlesSupport,particlesDomain,HOverEpsilon);
726 EMatrix<T, Eigen::Dynamic, Eigen::Dynamic> V(verletList.getNNPart(p), monomialBasis.size());
727 vandermonde.getMatrix(V);
729 T eps = vandermonde.getEps();
730 avgSpacingGlobal+=eps;
731 T tSpacing = vandermonde.getMinSpacing();
732 avgSpacingGlobal2+=tSpacing;
733 if(tSpacing>maxSpacingGlobal)
735 maxSpacingGlobal=tSpacing;
737 if(tSpacing<minSpacingGlobal)
739 minSpacingGlobal=tSpacing;
742 localEps.get(p.getKey()) = eps;
743 localEpsInvPow.get(p.getKey()) = 1.0 / openfpm::math::intpowlog(eps,differentialOrder);
746 EMatrix<T, Eigen::Dynamic, Eigen::Dynamic> E(verletList.getNNPart(p), verletList.getNNPart(p));
748 assert(verletList.getNNPart(p) >= monomialBasis.size());
749 assert(E.rows() == verletList.getNNPart(p));
750 assert(E.cols() == verletList.getNNPart(p));
753 diagonalScalingMatrix.buildMatrix(E, p, verletIt, eps, particlesSupport, particlesDomain);
755 EMatrix<T, Eigen::Dynamic, Eigen::Dynamic> B = E * V;
757 EMatrix<T, Eigen::Dynamic, Eigen::Dynamic> A = B.transpose() * B;
761 EMatrix<T, Eigen::Dynamic, 1> b(monomialBasis.size(), 1);
762 rhs.template getVector<T>(b);
764 EMatrix<T, Eigen::Dynamic, 1> a(monomialBasis.size(), 1);
766 a = A.colPivHouseholderQr().solve(b);
768 kerOffsets.get(p.getKey()) = calcKernels.
size();
773 unsigned matVRow = 0;
774 while (verletIt.isNext())
776 size_t q = verletIt.get();
779 calcKernels.add(computeKernel(x_pqNorm, a, V, matVRow, monomialBasis.getElements().size()));
787 v_cl.sum(avgSpacingGlobal);
788 v_cl.sum(avgSpacingGlobal2);
789 v_cl.max(maxSpacingGlobal);
790 v_cl.min(minSpacingGlobal);
794 {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;}
798 T computeKernel(
Point<dim, T> x, EMatrix<T, Eigen::Dynamic, 1> & a, EMatrix<T, Eigen::Dynamic, Eigen::Dynamic>& V,
size_t matVRow,
size_t monomialBasisSize)
const {
800 T expFactor = exp(-norm2(x));
802 for (
size_t i = 0; i < monomialBasisSize; ++i)
805 T mbValue = V(matVRow, i);
806 res += coeff * mbValue * expFactor;
812 T conditionNumber(
const EMatrix<T, -1, -1> &V, T condTOL)
const {
813 Eigen::JacobiSVD<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>> svd(V);
814 T cond = svd.singularValues()(0)
815 / svd.singularValues()(svd.singularValues().size() - 1);
816 if (cond > condTOL) {
818 <<
"WARNING: cond(V) = " << cond
819 <<
" is greater than TOL = " << condTOL
820 <<
", numPoints(V) = " << V.rows()
829 template<
unsigned int dim,
typename VerletList_type,
typename vector_type,
typename vector_type2=vector_type>
830 class SurfaceDcpse : Dcpse<dim, VerletList_type, vector_type, vector_type2> {
832 typedef typename vector_type::stype T;
841 bool isSurfaceDerivative=
false;
842 size_t initialParticleSize;
853 template<
unsigned int NORMAL_ID>
854 void createNormalParticles()
856 this->particlesSupport.template ghost_get<NORMAL_ID>(SKIP_LABELLING);
858 T nSpacing_p = nSpacing;
861 while (it.isNext()) {
864 Point<dim,T> xp=this->particlesSupport.
getPos(p), Normals=this->particlesSupport.template getProp<NORMAL_ID>(p);
866 if (this->opt == support_options::ADAPTIVE)
867 nSpacing_p = nSpacings.get(p);
869 for(
int i=1;i<=nCount;i++) {
871 for(
size_t j=0;j<dim;j++)
872 this->particlesSupport.
getLastPosEnd()[j] = xp[j]+i*nSpacing_p*Normals[j];
875 for(
size_t j=0;j<dim;j++)
876 this->particlesSupport.
getLastPosEnd()[j] = xp[j]-i*nSpacing_p*Normals[j];
881 if (this->opt==support_options::ADAPTIVE)
886 while (it.isNext()) {
889 rCuts.get(rCuts.
size()-1) = this->verletList.getRCuts(p);
892 this->verletList.clear();
894 if (rCuts.
size() != this->particlesDomain.size_local())
896 std::cerr << __FILE__ <<
":" << __LINE__
897 <<
" ERROR: when updating adaptive cut-off Verlet list in createNormalParticles, rCuts.size() != particlesDomain.size_local(), ["
898 << rCuts.
size() <<
"!=" << this->particlesDomain.
size_local() <<
"]" << std::endl;
899 std::runtime_error(
"Runtime adaptive cut-off Verlet list error");
904 this->verletList.fillNonSymmAdaptiveIterator(domainIt,
905 this->particlesDomain.getPosVector(),
906 this->particlesSupport.getPosVector(),
913 this->verletList.initCl(
914 this->verletList.getInternalCellList(),
915 this->particlesSupport.getPosVector(),
916 this->particlesSupport.size_local()
920 this->verletList.Initialize(
921 this->verletList.getInternalCellList(),
922 this->verletList.getRCut(),
924 this->particlesDomain.getPosVector(),
925 this->particlesSupport.getPosVector(),
926 this->particlesDomain.size_local()
945 void accumulateAndDeleteNormalParticles()
947 accCalcKernels.clear();
948 accKerOffsets.clear();
949 accKerOffsets.resize(this->particlesDomain.
size_local());
950 accKerOffsets.fill(-1);
956 while (it.isNext()) {
957 supportBuffer.clear();
961 size_t kerOff = this->kerOffsets.get(p);
963 accKerOffsets.get(p)=accCalcKernels.
size();
964 auto verletIt = this->verletList.getNNIterator(p);
967 while (verletIt.isNext())
969 size_t q = verletIt.get();
971 int difference =
static_cast<int>(q) -
static_cast<int>(initialParticleSize);
976 if (std::signbit(difference))
981 real_particle = difference / (2 * nCount);
983 auto found=nMap.find(real_particle);
985 if (found != nMap.end())
986 accCalcKernels.get(found->second) += this->calcKernels.get(kerOff+i);
990 supportBuffer.get(supportBuffer.
size()-1) = real_particle;
991 accCalcKernels.add();
992 accCalcKernels.get(accCalcKernels.
size()-1) = this->calcKernels.get(kerOff+i);
993 nMap[real_particle]=accCalcKernels.
size()-1;
999 this->verletList.clear(p);
1002 for (
int i = 0; i < supportBuffer.
size(); ++i)
1003 this->verletList.addPart(p, supportBuffer.get(i));
1013 this->calcKernels.swap(accCalcKernels);
1014 this->kerOffsets.swap(accKerOffsets);
1035 template<
unsigned int NORMAL_ID>
1039 VerletList_type& verletList,
1041 unsigned int convergenceOrder,
1044 unsigned int nCount,
1045 value_t< NORMAL_ID >,
1046 support_options opt = support_options::RADIUS)
1048 Dcpse<dim, VerletList_type,
vector_type,
vector_type2>(particlesSupport, particlesDomain, verletList, differentialSignature, convergenceOrder, opt),
1049 isSurfaceDerivative(true),
1055 if(opt==support_options::ADAPTIVE) {
1057 particlesSupport.template ghost_get<0>();
1060 while (it.isNext()) {
1061 size_t p = it.get();
1067 if(opt!=support_options::LOAD) {
1068 createNormalParticles<NORMAL_ID>();
1070 particlesSupport.
write(
"WithNormalParticlesQC");
1074 this->initializeStaticSize(
1081 if(opt!=support_options::LOAD) {
1082 accumulateAndDeleteNormalParticles();
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
Grid key for a distributed grid.
size_t size_local() const
return the local size of vector_dist_ws
vector_dist_iterator_subset getDomainIterator() const
Get an iterator that traverse the particles in the domain.
auto getPos(size_t vec_key) -> decltype(vd.getPos(vec_key))
Get the position of an element.
void appendLocal()
Add at the END of local and ghost particle.
size_t size_local_with_ghost() const
return the local size of the vector
auto getPos(vect_dist_key_dx vec_key) -> decltype(vPos.template get< 0 >(vec_key.getKey()))
Get the position of an element.
vector_dist_iterator getDomainIterator() const
Get an iterator that traverse the particles in the domain.
bool write(std::string out, int opt=VTK_WRITER)
Output particle position and properties.
vector_dist_iterator getDomainAndGhostIterator() const
Get an iterator that traverse the particles in the domain.
auto getLastPosEnd() -> decltype(vPos.template get< 0 >(0))
Get the position of the last element after ghost.
void ghost_get_subset()
Stub does not do anything.
void discardLocalAppend(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...