sph_harm.hpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. #ifndef _SCTL_SPH_HARM_HPP_
  2. #define _SCTL_SPH_HARM_HPP_
  3. #define SCTL_SHMAXDEG 1024
  4. #include SCTL_INCLUDE(matrix.hpp)
  5. #include SCTL_INCLUDE(fft_wrapper.hpp)
  6. #include SCTL_INCLUDE(common.hpp)
  7. namespace SCTL_NAMESPACE {
  8. enum class SHCArrange {
  9. // (p+1) x (p+1) complex elements in row-major order.
  10. // A : { A(0,0), A(0,1), ... A(0,p), A(1,0), ... A(p,p) }
  11. // where, A(n,m) = { Ar(n,m), Ai(n,m) } (real and imaginary parts)
  12. ALL,
  13. // (p+1)(p+2)/2 complex elements in row-major order (lower triangular part)
  14. // A : { A(0,0), A(1,0), A(1,1), A(2,0), A(2,1), A(2,2), ... A(p,p) }
  15. // where, A(n,m) = { Ar(n,m), Ai(n,m) } (real and imaginary parts)
  16. ROW_MAJOR,
  17. // (p+1)(p+1) real elements in col-major order (non-zero lower triangular part)
  18. // A : { Ar(0,0), Ar(1,0), ... Ar(p,0), Ar(1,1), ... Ar(p,1), Ai(1,1), ... Ai(p,1), ..., Ar(p,p), Ai(p,p)
  19. // where, A(n,m) = { Ar(n,m), Ai(n,m) } (real and imaginary parts)
  20. COL_MAJOR_NONZERO
  21. };
  22. template <class Real> class SphericalHarmonics{
  23. static constexpr Integer COORD_DIM = 3;
  24. public:
  25. // Scalar Spherical Harmonics
  26. static void Grid2SHC(const Vector<Real>& X_in, Long Nt_in, Long Np_in, Long p_out, Vector<Real>& S_out, SHCArrange arrange_out);
  27. static void SHC2Grid(const Vector<Real>& S_in, SHCArrange arrange_in, Long p_in, Long Nt_out, Long Np_out, Vector<Real>* X_out, Vector<Real>* X_theta_out=nullptr, Vector<Real>* X_phi_out=nullptr);
  28. static void SHCEval(const Vector<Real>& S_in, SHCArrange arrange_in, Long p_in, const Vector<Real>& cos_theta_phi_in, Vector<Real>& X_out);
  29. static void SHC2Pole(const Vector<Real>& S_in, SHCArrange arrange_in, Long p_in, Vector<Real>& P_out);
  30. static void WriteVTK(const char* fname, const Vector<Real>* S, const Vector<Real>* f_val, SHCArrange arrange, Long p_in, Long p_out, Real period=0, const Comm& comm = Comm::World());
  31. // Vector Spherical Harmonics
  32. static void Grid2VecSHC(const Vector<Real>& X_in, Long Nt_in, Long Np_in, Long p_out, Vector<Real>& S_out, SHCArrange arrange_out);
  33. static void VecSHC2Grid(const Vector<Real>& S_in, SHCArrange arrange_in, Long p_in, Long Nt_out, Long Np_out, Vector<Real>& X_out);
  34. static void VecSHCEval(const Vector<Real>& S_in, SHCArrange arrange_in, Long p_in, const Vector<Real>& cos_theta_phi_in, Vector<Real>& X_out);
  35. static void StokesEvalSL(const Vector<Real>& S_in, SHCArrange arrange_in, Long p_in, const Vector<Real>& coord_in, Vector<Real>& X_out);
  36. static void StokesEvalDL(const Vector<Real>& S_in, SHCArrange arrange_in, Long p_in, const Vector<Real>& coord_in, Vector<Real>& X_out);
  37. static void test_stokes() {
  38. int p = 4;
  39. int dof = 3;
  40. int Nt = p+1, Np = 2*p+1;
  41. auto print_coeff = [&](Vector<Real> S) {
  42. Long idx=0;
  43. for (Long k=0;k<dof;k++) {
  44. for (Long n=0;n<=p;n++) {
  45. std::cout<<Vector<Real>(2*n+2, S.begin()+idx);
  46. idx+=2*n+2;
  47. }
  48. }
  49. std::cout<<'\n';
  50. };
  51. Vector<Real> f(dof * Nt * Np);
  52. { // Set f
  53. for (Long i = 0; i < Nt; i++) {
  54. for (Long j = 0; j < Np; j++) {
  55. f[(0 * Nt + i) * Np + j] = 3;
  56. f[(1 * Nt + i) * Np + j] = 2;
  57. f[(2 * Nt + i) * Np + j] = 1;
  58. }
  59. }
  60. }
  61. Vector<Real> f_coeff;
  62. Grid2VecSHC(f, Nt, Np, p, f_coeff, sctl::SHCArrange::ROW_MAJOR);
  63. print_coeff(f_coeff);
  64. for (Long i = 0; i < 20; i++) { // Evaluate
  65. Vector<Real> Df;
  66. Vector<Real> x(3);
  67. x[0] = drand48();
  68. x[1] = drand48();
  69. x[2] = drand48();
  70. Real R = sqrt<Real>(x[0]*x[0]+x[1]*x[1]+x[2]*x[2]);
  71. x[0]/=R*(i+0.5)/10;
  72. x[1]/=R*(i+0.5)/10;
  73. x[2]/=R*(i+0.5)/10;
  74. StokesEvalDL(f_coeff, sctl::SHCArrange::ROW_MAJOR, p, x, Df);
  75. std::cout<<Df+1e-10;
  76. }
  77. Clear();
  78. }
  79. static void test() {
  80. int p = 3;
  81. int dof = 1;
  82. int Nt = p+1, Np = 2*p+1;
  83. auto print_coeff = [&](Vector<Real> S) {
  84. Long idx=0;
  85. for (Long k=0;k<dof;k++) {
  86. for (Long n=0;n<=p;n++) {
  87. std::cout<<Vector<Real>(2*n+2, S.begin()+idx);
  88. idx+=2*n+2;
  89. }
  90. }
  91. std::cout<<'\n';
  92. };
  93. Vector<Real> r_theta_phi, theta_phi;
  94. { // Set r_theta_phi, theta_phi
  95. Vector<Real> leg_nodes = LegendreNodes(Nt-1);
  96. for (Long i=0;i<Nt;i++) {
  97. for (Long j=0;j<Np;j++) {
  98. r_theta_phi.PushBack(1);
  99. r_theta_phi.PushBack(leg_nodes[i]);
  100. r_theta_phi.PushBack(j * 2 * const_pi<Real>() / Np);
  101. theta_phi.PushBack(leg_nodes[i]);
  102. theta_phi.PushBack(j * 2 * const_pi<Real>() / Np);
  103. }
  104. }
  105. }
  106. int Ncoeff = (p + 1) * (p + 1);
  107. Vector<Real> Xcoeff(dof * Ncoeff), Xgrid;
  108. for (int i=0;i<Xcoeff.Dim();i++) Xcoeff[i]=i+1;
  109. SHC2Grid(Xcoeff, sctl::SHCArrange::COL_MAJOR_NONZERO, p, Nt, Np, &Xgrid);
  110. std::cout<<Matrix<Real>(Nt*dof, Np, Xgrid.begin())<<'\n';
  111. {
  112. Vector<Real> val;
  113. SHCEval(Xcoeff, sctl::SHCArrange::COL_MAJOR_NONZERO, p, theta_phi, val);
  114. Matrix<Real>(dof, val.Dim()/dof, val.begin(), false) = Matrix<Real>(val.Dim()/dof, dof, val.begin()).Transpose();
  115. std::cout<<Matrix<Real>(val.Dim()/Np, Np, val.begin()) - Matrix<Real>(Nt*dof, Np, Xgrid.begin())+1e-10<<'\n';
  116. }
  117. Grid2SHC(Xgrid, Nt, Np, p, Xcoeff, sctl::SHCArrange::ROW_MAJOR);
  118. print_coeff(Xcoeff);
  119. //SphericalHarmonics<Real>::WriteVTK("test", nullptr, &Xcoeff, sctl::SHCArrange::ROW_MAJOR, p, 32);
  120. Clear();
  121. }
  122. static void Clear() { MatrixStore().Resize(0); }
  123. private:
  124. // Probably don't work anymore, need to be updated :(
  125. static void SHC2GridTranspose(const Vector<Real>& X, Long p0, Long p1, Vector<Real>& S);
  126. static void RotateAll(const Vector<Real>& S, Long p0, Long dof, Vector<Real>& S_);
  127. static void RotateTranspose(const Vector<Real>& S_, Long p0, Long dof, Vector<Real>& S);
  128. static void StokesSingularInteg(const Vector<Real>& S, Long p0, Long p1, Vector<Real>* SLMatrix=nullptr, Vector<Real>* DLMatrix=nullptr);
  129. static void Grid2SHC_(const Vector<Real>& X, Long Nt, Long Np, Long p, Vector<Real>& B1);
  130. static void SHCArrange0(const Vector<Real>& B1, Long p, Vector<Real>& S, SHCArrange arrange);
  131. static void SHC2Grid_(const Vector<Real>& S, Long p, Long Nt, Long Np, Vector<Real>* X, Vector<Real>* X_theta=nullptr, Vector<Real>* X_phi=nullptr);
  132. static void SHCArrange1(const Vector<Real>& S_in, SHCArrange arrange_out, Long p, Vector<Real>& S_out);
  133. /**
  134. * \brief Computes all the Associated Legendre Polynomials (normalized) up to the specified degree.
  135. * \param[in] degree The degree up to which the Legendre polynomials have to be computed.
  136. * \param[in] X The input values for which the polynomials have to be computed.
  137. * \param[in] N The number of input points.
  138. * \param[out] poly_val The output array of size (degree+1)*(degree+2)*N/2 containing the computed polynomial values.
  139. * The output values are in the order:
  140. * P(n,m)[i] => {P(0,0)[0], P(0,0)[1], ..., P(0,0)[N-1], P(1,0)[0], ..., P(1,0)[N-1],
  141. * P(2,0)[0], ..., P(degree,0)[N-1], P(1,1)[0], ...,P(2,1)[0], ..., P(degree,degree)[N-1]}
  142. */
  143. static void LegPoly(Vector<Real>& poly_val, const Vector<Real>& X, Long degree);
  144. static void LegPolyDeriv(Vector<Real>& poly_val, const Vector<Real>& X, Long degree);
  145. static const Vector<Real>& LegendreNodes(Long p1);
  146. static const Vector<Real>& LegendreWeights(Long p1);
  147. static const Vector<Real>& SingularWeights(Long p1);
  148. static const Matrix<Real>& MatFourier(Long p0, Long p1);
  149. static const Matrix<Real>& MatFourierInv(Long p0, Long p1);
  150. static const Matrix<Real>& MatFourierGrad(Long p0, Long p1);
  151. static const FFT<Real>& OpFourier(Long Np);
  152. static const FFT<Real>& OpFourierInv(Long Np);
  153. static const std::vector<Matrix<Real>>& MatLegendre(Long p0, Long p1);
  154. static const std::vector<Matrix<Real>>& MatLegendreInv(Long p0, Long p1);
  155. static const std::vector<Matrix<Real>>& MatLegendreGrad(Long p0, Long p1);
  156. // Evaluate all Spherical Harmonic basis functions up to order p at (theta, phi) coordinates.
  157. static void SHBasisEval(Long p, const Vector<Real>& cos_theta_phi, Matrix<Real>& M);
  158. static void VecSHBasisEval(Long p, const Vector<Real>& cos_theta_phi, Matrix<Real>& M);
  159. static const std::vector<Matrix<Real>>& MatRotate(Long p0);
  160. template <bool SLayer, bool DLayer> static void StokesSingularInteg_(const Vector<Real>& X0, Long p0, Long p1, Vector<Real>& SL, Vector<Real>& DL);
  161. struct MatrixStorage{
  162. MatrixStorage(){
  163. const Long size = SCTL_SHMAXDEG;
  164. Resize(size);
  165. }
  166. void Resize(Long size){
  167. Qx_ .resize(size);
  168. Qw_ .resize(size);
  169. Sw_ .resize(size);
  170. Mf_ .resize(size*size);
  171. Mdf_.resize(size*size);
  172. Ml_ .resize(size*size);
  173. Mdl_.resize(size*size);
  174. Mr_ .resize(size);
  175. Mfinv_ .resize(size*size);
  176. Mlinv_ .resize(size*size);
  177. Mfft_.resize(size);
  178. Mfftinv_.resize(size);
  179. }
  180. std::vector<Vector<Real>> Qx_;
  181. std::vector<Vector<Real>> Qw_;
  182. std::vector<Vector<Real>> Sw_;
  183. std::vector<Matrix<Real>> Mf_ ;
  184. std::vector<Matrix<Real>> Mdf_;
  185. std::vector<std::vector<Matrix<Real>>> Ml_ ;
  186. std::vector<std::vector<Matrix<Real>>> Mdl_;
  187. std::vector<std::vector<Matrix<Real>>> Mr_;
  188. std::vector<Matrix<Real>> Mfinv_ ;
  189. std::vector<std::vector<Matrix<Real>>> Mlinv_ ;
  190. std::vector<FFT<Real>> Mfft_;
  191. std::vector<FFT<Real>> Mfftinv_;
  192. };
  193. static MatrixStorage& MatrixStore(){
  194. static MatrixStorage storage;
  195. return storage;
  196. }
  197. };
  198. template class SphericalHarmonics<double>;
  199. } // end namespace
  200. #include SCTL_INCLUDE(sph_harm.txx)
  201. #endif // _SCTL_SPH_HARM_HPP_