void evaluate( const ConstGeometricalDataSlice<CoordinateType>& testGeomData, const ConstGeometricalDataSlice<CoordinateType>& trialGeomData, CollectionOf2dSlicesOfNdArrays<ValueType>& result) const { const int coordCount = 3; assert(testGeomData.dimWorld() == coordCount); assert(result.size() == 1); CoordinateType distanceSq = 0.; CoordinateType nTest_diff = 0; CoordinateType nTrial_diff = 0; CoordinateType nTest_nTrial = 0.; for (int coordIndex = 0; coordIndex < coordCount; ++coordIndex) { CoordinateType diff = trialGeomData.global(coordIndex) - testGeomData.global(coordIndex); distanceSq += diff * diff; nTest_diff += diff * testGeomData.normal(coordIndex); nTrial_diff += diff * trialGeomData.normal(coordIndex); nTest_nTrial += testGeomData.normal(coordIndex) * trialGeomData.normal(coordIndex); } CoordinateType distance = sqrt(distanceSq); CoordinateType commonFactor = static_cast<CoordinateType>(-1. / (4. * M_PI)) / (distance * distanceSq * distanceSq); result[0](0, 0) = commonFactor * ( nTest_nTrial * distanceSq - static_cast<CoordinateType>(3.) * nTest_diff * nTrial_diff); }
void evaluate(const ConstGeometricalDataSlice<CoordinateType> &testGeomData, const ConstGeometricalDataSlice<CoordinateType> &trialGeomData, CollectionOf2dSlicesOfNdArrays<ValueType> &result) const { const int coordCount = 3; assert(testGeomData.dimWorld() == coordCount); assert(result.size() == 1); ValueType sum = 0; for (int coordIndex = 0; coordIndex < coordCount; ++coordIndex) { ValueType diff = testGeomData.global(coordIndex) - trialGeomData.global(coordIndex); sum += diff * diff; } result[0](0, 0) = static_cast<CoordinateType>(1. / (4. * M_PI)) / sqrt(sum); }
void evaluate( const ConstGeometricalDataSlice<CoordinateType>& testGeomData, const ConstGeometricalDataSlice<CoordinateType>& trialGeomData, CollectionOf2dSlicesOfNdArrays<ValueType>& result) const { const int coordCount = 3; assert(testGeomData.dimWorld() == coordCount); assert(result.size() == 1); /* Define coefficients for the regular part of the periodic Green's kernel for the 3D Laplace equation in a periodic box of size 1. * We use here an expansion with harmonics up to degree 20, which yields an approximation correct up to precision 1e-10. * The singular part contains the 27 Green's function for the neighbouring cells and a corrective term for a uniform neutralizing * background charge. */ const int deg_max = 9; const CoordinateType Harmonic_Coefficients[34] = { 0.01101709645861367, 0.01316794887913183, 5.954412827470426e-05, -0.0002227937273979395, 0.0002062746586075765, 0.0001551394663489125, 0.0002363741367920927, 5.288864558642977e-06, -1.065878569810829e-05, -1.268649253304447e-05, 2.855411046592645e-05, 2.503036078346336e-05, 1.043475591993333e-05, 3.395059459839415e-05, 1.255601659344675e-06, -1.846641841052362e-06, -1.981606873099481e-06, -2.406130170392715e-06, 1.25747200483749e-06, 6.475400668217489e-07, 7.957080434716371e-07, 9.28658402338717e-07, 1.321949011147113e-06, 9.74822898071474e-08, -1.330176890868469e-07, -4.957180138283109e-08, -2.127820763047173e-07, -1.370001191920438e-07, 2.762838013591894e-08, -5.682089767011293e-09, 1.844902148801811e-08, 2.90202283948248e-08, 3.429155607637934e-08, 1.998351880226059e-08 }; const CoordinateType rescaling = static_cast<CoordinateType>( 3/(2.*M_PI) + 3/(sqrt(2)*M_PI) + 2/(sqrt(3)*M_PI)); CoordinateType ri2[3*coordCount]; CoordinateType r2 = 0; CoordinateType diff[3]; ValueType res = 0; const CoordinateType common = static_cast<CoordinateType>(1. / (4. * M_PI)); const CoordinateType ONE = static_cast<CoordinateType>(1.); for (int coordIndex = 0; coordIndex < coordCount; ++coordIndex) { diff[coordIndex] = boost::math::tools::fmod_workaround(testGeomData.global(coordIndex) - trialGeomData.global(coordIndex) + static_cast<CoordinateType>(0.5), ONE); if (diff[coordIndex] > 0) diff[coordIndex] -= static_cast<CoordinateType>(0.5); else diff[coordIndex] += static_cast<CoordinateType>(0.5); // Periodization ri2[ 3*coordIndex] = (diff[coordIndex]-ONE)*(diff[coordIndex]-ONE); ri2[1+3*coordIndex] = diff[coordIndex]*diff[coordIndex]; ri2[2+3*coordIndex] = (diff[coordIndex]+ONE)*(diff[coordIndex]+ONE); r2 += ri2[1+3*coordIndex]; } // Loop over the 27 adjacent cells (!) for (int i = 0; i < 3; ++i) { for (int j = 3; j < 6; ++j) { for (int k = 6; k < 9; ++k) { res += common / sqrt(ri2[i] + ri2[j] + ri2[k]); } } } // corrective term for a neutral background charge res += static_cast<CoordinateType>(1./6.) * r2 - rescaling; // Approximation of the correction using spherical harmonics int ind = 0; // Transform to spherical coordinates CoordinateType rdegree = r2; CoordinateType rfactor = sqrt(r2), theta = acos(diff[2]/sqrt(r2)), phi = atan2(diff[1], diff[0]); for (int degree = 4; degree < deg_max; degree += 2) { rdegree = rdegree * r2; for (int order = 0; order < degree + 1; order += 4) { res += Harmonic_Coefficients[ind] * boost::math::spherical_harmonic_r(degree, order, theta, phi) * rdegree; ++ind; } } result[0](0, 0) = res; }