|
@@ -1407,6 +1407,208 @@ template <class Real> void SphericalHarmonics<Real>::StokesEvalKL(const Vector<R
|
|
|
}
|
|
|
|
|
|
|
|
|
+template <class Real> void SphericalHarmonics<Real>::StokesEvalKSelf(const Vector<Real>& S, SHCArrange arrange, Long p0, const Vector<Real>& coord, bool interior, Vector<Real>& X) {
|
|
|
+ Long M = (p0+1) * (p0+1);
|
|
|
+
|
|
|
+ Long dof;
|
|
|
+ Matrix<Real> B1;
|
|
|
+ { // Set B1, dof
|
|
|
+ Vector<Real> B0;
|
|
|
+ SHCArrange1(S, arrange, p0, B0);
|
|
|
+ dof = B0.Dim() / M / COORD_DIM;
|
|
|
+ assert(B0.Dim() == dof * COORD_DIM * M);
|
|
|
+
|
|
|
+ B1.ReInit(dof, COORD_DIM * M);
|
|
|
+ Vector<Real> B1_(B1.Dim(0) * B1.Dim(1), B1.begin(), false);
|
|
|
+ SHCArrange0(B0, p0, B1_, SHCArrange::COL_MAJOR_NONZERO);
|
|
|
+ }
|
|
|
+ assert(B1.Dim(1) == COORD_DIM * M);
|
|
|
+ assert(B1.Dim(0) == dof);
|
|
|
+
|
|
|
+ Long N, p_;
|
|
|
+ Matrix<Real> SHBasis;
|
|
|
+ Vector<Real> R, theta_phi;
|
|
|
+ { // Set N, p_, R, SHBasis
|
|
|
+ p_ = p0 + 1;
|
|
|
+ Real M_ = (p_+1) * (p_+1);
|
|
|
+ N = coord.Dim() / COORD_DIM;
|
|
|
+ assert(coord.Dim() == N * COORD_DIM);
|
|
|
+
|
|
|
+ R.ReInit(N);
|
|
|
+ theta_phi.ReInit(2 * N);
|
|
|
+ for (Long i = 0; i < N; i++) { // Set R, theta_phi
|
|
|
+ ConstIterator<Real> x = coord.begin() + i * COORD_DIM;
|
|
|
+ R[i] = sqrt<Real>(x[0]*x[0] + x[1]*x[1] + x[2]*x[2]);
|
|
|
+ theta_phi[i * 2 + 0] = atan2(sqrt<Real>(x[0]*x[0] + x[1]*x[1]), x[2]);
|
|
|
+ theta_phi[i * 2 + 1] = atan2(x[1], x[0]);
|
|
|
+ }
|
|
|
+ SHBasisEval(p_, theta_phi, SHBasis);
|
|
|
+ assert(SHBasis.Dim(1) == M_);
|
|
|
+ assert(SHBasis.Dim(0) == N);
|
|
|
+ SCTL_UNUSED(M_);
|
|
|
+ }
|
|
|
+
|
|
|
+ Matrix<Real> StokesOp(N * COORD_DIM, COORD_DIM * M);
|
|
|
+ for (Long i = 0; i < N; i++) { // Set StokesOp
|
|
|
+
|
|
|
+ Real cos_theta, sin_theta, csc_theta, cos_phi, sin_phi;
|
|
|
+ { // Set cos_theta, csc_theta, cos_phi, sin_phi
|
|
|
+ cos_theta = cos(theta_phi[i * 2 + 0]);
|
|
|
+ sin_theta = sin(theta_phi[i * 2 + 0]);
|
|
|
+ csc_theta = 1 / sin_theta;
|
|
|
+ cos_phi = cos(theta_phi[i * 2 + 1]);
|
|
|
+ sin_phi = sin(theta_phi[i * 2 + 1]);
|
|
|
+ }
|
|
|
+ Complex<Real> imag(0,1), exp_phi(cos_phi, -sin_phi);
|
|
|
+
|
|
|
+ for (Long m = 0; m <= p0; m++) {
|
|
|
+ for (Long n = m; n <= p0; n++) {
|
|
|
+ auto write_coeff = [&](Complex<Real> c, Long n, Long m, Long k0, Long k1) {
|
|
|
+ if (0 <= m && m <= n && n <= p0 && 0 <= k0 && k0 < COORD_DIM && 0 <= k1 && k1 < COORD_DIM) {
|
|
|
+ Long idx = (2 * p0 - m + 2) * m - (m ? p0+1 : 0) + n;
|
|
|
+ StokesOp[i * COORD_DIM + k1][k0 * M + idx] = c.real;
|
|
|
+ if (m) {
|
|
|
+ idx += (p0+1-m);
|
|
|
+ StokesOp[i * COORD_DIM + k1][k0 * M + idx] = c.imag;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ Complex<Real> Vr, Vt, Vp, Wr, Wt, Wp, Xr, Xt, Xp;
|
|
|
+ { // Set vector spherical harmonics
|
|
|
+ auto Y = [&SHBasis,p_,i](Long n, Long m) {
|
|
|
+ Complex<Real> c;
|
|
|
+ if (0 <= m && m <= n && n <= p_) {
|
|
|
+ Long idx = (2 * p_ - m + 2) * m - (m ? p_+1 : 0) + n;
|
|
|
+ c.real = SHBasis[i][idx];
|
|
|
+ if (m) {
|
|
|
+ idx += (p_+1-m);
|
|
|
+ c.imag = SHBasis[i][idx];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return c;
|
|
|
+ };
|
|
|
+ auto Yt = [exp_phi, &Y, &R, i](Long n, Long m) {
|
|
|
+ auto A = (0<=n && m<=n ? 0.5 * sqrt<Real>((n+m)*(n-m+1)) * (m-1==0?2.0:1.0) : 0);
|
|
|
+ auto B = (0<=n && m<=n ? 0.5 * sqrt<Real>((n-m)*(n+m+1)) * (m+1==0?2.0:1.0) : 0);
|
|
|
+ return (B / exp_phi * Y(n, m + 1) - A * exp_phi * Y(n, m - 1)) / R[i];
|
|
|
+ };
|
|
|
+ Complex<Real> Y_1 = Y(n + 0, m);
|
|
|
+ Complex<Real> Y_1t = Yt(n + 0, m);
|
|
|
+
|
|
|
+ Complex<Real> Ycsc_1 = Y_1 * csc_theta;
|
|
|
+ if (fabs(sin_theta) == 0) {
|
|
|
+ auto Y_csc0 = [exp_phi, cos_theta](Long n, Long m) {
|
|
|
+ if (m == 1) return -sqrt<Real>((2*n+1)*n*(n+1)) * ((n%2==0) && (cos_theta<0) ? -1 : 1) * exp_phi;
|
|
|
+ return Complex<Real>(0, 0);
|
|
|
+ };
|
|
|
+ Ycsc_1 = Y_csc0(n + 0, m);
|
|
|
+ }
|
|
|
+
|
|
|
+ auto SetVecSH = [&imag,n,m](Complex<Real>& Vr, Complex<Real>& Vt, Complex<Real>& Vp, Complex<Real>& Wr, Complex<Real>& Wt, Complex<Real>& Wp, Complex<Real>& Xr, Complex<Real>& Xt, Complex<Real>& Xp, const Complex<Real> C0, const Complex<Real> C1, const Complex<Real> C2) {
|
|
|
+ Vr = C0 * (-n-1);
|
|
|
+ Vt = C2;
|
|
|
+ Vp = -imag * m * C1;
|
|
|
+
|
|
|
+ Wr = C0 * n;
|
|
|
+ Wt = C2;
|
|
|
+ Wp = -imag * m * C1;
|
|
|
+
|
|
|
+ Xr = 0;
|
|
|
+ Xt = imag * m * C1;
|
|
|
+ Xp = C2;
|
|
|
+ };
|
|
|
+ { // Set Vr, Vt, Vp, Wr, Wt, Wp, Xr, Xt, Xp
|
|
|
+ auto C0 = Y_1;
|
|
|
+ auto C1 = Ycsc_1;
|
|
|
+ auto C2 = Y_1t * R[i];
|
|
|
+ SetVecSH(Vr, Vt, Vp, Wr, Wt, Wp, Xr, Xt, Xp, C0, C1, C2);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Complex<Real> SVr, SVt, SVp;
|
|
|
+ Complex<Real> SWr, SWt, SWp;
|
|
|
+ Complex<Real> SXr, SXt, SXp;
|
|
|
+ if (interior) {
|
|
|
+ Real a,b;
|
|
|
+ a = ((2*n*n+4*n+3) / (Real)((2*n+1) *(2*n+3)) )*pow<Real>(R[i],n);
|
|
|
+ b = ((n+1)*(n-1) / (Real) (2*n+1) )*(pow<Real>(R[i],n) - pow<Real>(R[i],n-2));
|
|
|
+ SVr = a * Vr + b * Wr;
|
|
|
+ SVt = a * Vt + b * Wt;
|
|
|
+ SVp = a * Vp + b * Wp;
|
|
|
+
|
|
|
+ a = (2*(n+1)*(n-1) / (Real)((2*n+1) * (2*n-1))) * pow<Real>(R[i], n-2);
|
|
|
+ SWr = a * Wr;
|
|
|
+ SWt = a * Wt;
|
|
|
+ SWp = a * Wp;
|
|
|
+
|
|
|
+ a = ((n-1) / (Real)(2*n+1)) * pow<Real>(R[i], n-1);
|
|
|
+ SXr = a * Xr;
|
|
|
+ SXt = a * Xt;
|
|
|
+ SXp = a * Xp;
|
|
|
+ } else {
|
|
|
+ Real a,b;
|
|
|
+ a = -2*n*(n+2) / (Real)((2*n+1) * (2*n+3)) * pow<Real>(R[i], -n-3);
|
|
|
+ SVr = a * Vr;
|
|
|
+ SVt = a * Vt;
|
|
|
+ SVp = a * Vp;
|
|
|
+
|
|
|
+ a = -(2*n*n+1) / (Real)((2*n+1) * (2*n-1)) * pow<Real>(R[i], -n-1);
|
|
|
+ b = n*(n+2) / (Real)(2*n+1) * (pow<Real>(R[i], -n-1) - pow<Real>(R[i], -n-3));
|
|
|
+ SWr = a * Wr + b * Vr;
|
|
|
+ SWt = a * Wt + b * Vt;
|
|
|
+ SWp = a * Wp + b * Vp;
|
|
|
+
|
|
|
+ a = -(n+2) / (Real)(2*n+1) * pow<Real>(R[i], -n-2);
|
|
|
+ SXr = a * Xr;
|
|
|
+ SXt = a * Xt;
|
|
|
+ SXp = a * Xp;
|
|
|
+ }
|
|
|
+
|
|
|
+ write_coeff(SVr, n, m, 0, 0);
|
|
|
+ write_coeff(SVt, n, m, 0, 1);
|
|
|
+ write_coeff(SVp, n, m, 0, 2);
|
|
|
+
|
|
|
+ write_coeff(SWr, n, m, 1, 0);
|
|
|
+ write_coeff(SWt, n, m, 1, 1);
|
|
|
+ write_coeff(SWp, n, m, 1, 2);
|
|
|
+
|
|
|
+ write_coeff(SXr, n, m, 2, 0);
|
|
|
+ write_coeff(SXt, n, m, 2, 1);
|
|
|
+ write_coeff(SXp, n, m, 2, 2);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ { // Set X <-- Q * StokesOp * B1
|
|
|
+ if (X.Dim() != N * dof * COORD_DIM) X.ReInit(N * dof * COORD_DIM);
|
|
|
+ for (Long k0 = 0; k0 < N; k0++) {
|
|
|
+ StaticArray<Real,9> Q;
|
|
|
+ { // Set Q
|
|
|
+ Real cos_theta = cos(theta_phi[k0 * 2 + 0]);
|
|
|
+ Real sin_theta = sin(theta_phi[k0 * 2 + 0]);
|
|
|
+ Real cos_phi = cos(theta_phi[k0 * 2 + 1]);
|
|
|
+ Real sin_phi = sin(theta_phi[k0 * 2 + 1]);
|
|
|
+ Q[0] = sin_theta*cos_phi; Q[1] = sin_theta*sin_phi; Q[2] = cos_theta;
|
|
|
+ Q[3] = cos_theta*cos_phi; Q[4] = cos_theta*sin_phi; Q[5] =-sin_theta;
|
|
|
+ Q[6] = -sin_phi; Q[7] = cos_phi; Q[8] = 0;
|
|
|
+ }
|
|
|
+ for (Long k1 = 0; k1 < dof; k1++) { // Set X <-- Q * StokesOp * B1
|
|
|
+ StaticArray<Real,COORD_DIM> in;
|
|
|
+ for (Long j = 0; j < COORD_DIM; j++) {
|
|
|
+ in[j] = 0;
|
|
|
+ for (Long i = 0; i < COORD_DIM * M; i++) {
|
|
|
+ in[j] += B1[k1][i] * StokesOp[k0 * COORD_DIM + j][i];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ X[(k0 * dof + k1) * COORD_DIM + 0] = Q[0] * in[0] + Q[3] * in[1] + Q[6] * in[2];
|
|
|
+ X[(k0 * dof + k1) * COORD_DIM + 1] = Q[1] * in[0] + Q[4] * in[1] + Q[7] * in[2];
|
|
|
+ X[(k0 * dof + k1) * COORD_DIM + 2] = Q[2] * in[0] + Q[5] * in[1] + Q[8] * in[2];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
|
|
|
|