|
@@ -1,6 +1,7 @@
|
|
|
#ifndef _SCTL_BOUNDARY_QUADRATURE_HPP_
|
|
|
#define _SCTL_BOUNDARY_QUADRATURE_HPP_
|
|
|
|
|
|
+#include <biest.hpp>
|
|
|
#include <mutex>
|
|
|
#include <atomic>
|
|
|
#include <tuple>
|
|
@@ -2079,6 +2080,31 @@ template <class Real, Integer ORDER=10> class Stellarator {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+ struct BiotSavartGrad3D {
|
|
|
+ template <class ValueType> static constexpr ValueType ScaleFactor() {
|
|
|
+ return 1 / (4 * const_pi<ValueType>());
|
|
|
+ }
|
|
|
+ template <class ValueType> static void Eval(ValueType (&u)[3][9], const ValueType (&r)[3], const ValueType (&n)[3], void* ctx_ptr) {
|
|
|
+ ValueType r2 = r[0]*r[0]+r[1]*r[1]+r[2]*r[2];
|
|
|
+ ValueType rinv = (r2>1e-16 ? 1/sqrt<ValueType>(r2) : 0);
|
|
|
+ ValueType rinv2 = rinv * rinv;
|
|
|
+ ValueType rinv3 = rinv2 * rinv;
|
|
|
+ ValueType rinv5 = rinv2 * rinv3;
|
|
|
+
|
|
|
+ u[0][0] = 0; u[1][0] = - 3 * r[2] * r[0] * rinv5; u[2][0] = 3 * r[1] * r[0] * rinv5;
|
|
|
+ u[0][1] = 0; u[1][0] = - 3 * r[2] * r[1] * rinv5; u[2][0] = -(1) * rinv3 + 3 * r[1] * r[1] * rinv5;
|
|
|
+ u[0][2] = 0; u[1][0] = (1) * rinv3 - 3 * r[2] * r[2] * rinv5; u[2][0] = 3 * r[1] * r[2] * rinv5;
|
|
|
+
|
|
|
+ u[0][3] = 3 * r[2] * r[0] * rinv5; u[1][1] = 0; u[2][1] = (1) * rinv3 - 3 * r[0] * r[0] * rinv5;
|
|
|
+ u[0][4] = 3 * r[2] * r[1] * rinv5; u[1][1] = 0; u[2][1] = - 3 * r[0] * r[1] * rinv5;
|
|
|
+ u[0][5] = -(1) * rinv3 + 3 * r[2] * r[2] * rinv5; u[1][1] = 0; u[2][1] = - 3 * r[0] * r[2] * rinv5;
|
|
|
+
|
|
|
+ u[0][6] = - 3 * r[1] * r[0] * rinv5; u[1][2] = -(1) * rinv3 + 3 * r[0] * r[0] * rinv5; u[2][2] = 0;
|
|
|
+ u[0][7] = (1) * rinv3 - 3 * r[1] * r[1] * rinv5; u[1][2] = 3 * r[0] * r[1] * rinv5; u[2][2] = 0;
|
|
|
+ u[0][8] = - 3 * r[1] * r[2] * rinv5; u[1][2] = 3 * r[0] * r[2] * rinv5; u[2][2] = 0;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
struct Laplace3D_dUxD {
|
|
|
template <class ValueType> static constexpr ValueType ScaleFactor() {
|
|
|
return 1 / (4 * const_pi<ValueType>());
|
|
@@ -2147,6 +2173,12 @@ template <class Real, Integer ORDER=10> class Stellarator {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+ static Real max_norm(const sctl::Vector<Real>& x) {
|
|
|
+ Real err = 0;
|
|
|
+ for (const auto& a : x) err = std::max(err, sctl::fabs<Real>(a));
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+
|
|
|
public:
|
|
|
Stellarator(const Vector<Long>& NtNp = Vector<Long>()) {
|
|
|
NtNp_ = NtNp;
|
|
@@ -2182,12 +2214,28 @@ template <class Real, Integer ORDER=10> class Stellarator {
|
|
|
return elements;
|
|
|
}
|
|
|
|
|
|
+ Long Nsurf() const {
|
|
|
+ return elem_dsp.Dim();
|
|
|
+ }
|
|
|
+ Long ElemDsp(Long s) const {
|
|
|
+ return elem_dsp[s];
|
|
|
+ }
|
|
|
+ Long NTor(Long s) const {
|
|
|
+ return NtNp_[s*2+0];
|
|
|
+ }
|
|
|
+ Long NPol(Long s) const {
|
|
|
+ return NtNp_[s*2+1];
|
|
|
+ }
|
|
|
+
|
|
|
static void test() {
|
|
|
constexpr Integer order_singular = 15;
|
|
|
constexpr Integer order_direct = 35;
|
|
|
Comm comm = Comm::World();
|
|
|
Profile::Enable(true);
|
|
|
|
|
|
+ Real gmres_tol = 1e-8;
|
|
|
+ Long max_iter = 100;
|
|
|
+
|
|
|
Stellarator<Real,ORDER> S;
|
|
|
{ // Init S
|
|
|
Vector<Long> NtNp;
|
|
@@ -2196,6 +2244,151 @@ template <class Real, Integer ORDER=10> class Stellarator {
|
|
|
S = Stellarator<Real,ORDER>(NtNp);
|
|
|
}
|
|
|
|
|
|
+ auto cheb2grid = [] (const Vector<ElemBasis>& X, Long Mt, Long Mp, Long Nt, Long Np) {
|
|
|
+ const Long dof = X.Dim() / (Mt * Mp);
|
|
|
+ SCTL_ASSERT(X.Dim() == Mt * Mp *dof);
|
|
|
+
|
|
|
+ Vector<Real> Xf(dof*Nt*Np); Xf = 0;
|
|
|
+ const Long Nnodes = ElemBasis::Size();
|
|
|
+ const Matrix<Real>& Mnodes = Basis<Real,1,ORDER>::Nodes();
|
|
|
+ for (Long t = 0; t < Nt; t++) {
|
|
|
+ for (Long p = 0; p < Np; p++) {
|
|
|
+ Real theta = t / (Real)Nt;
|
|
|
+ Real phi = p / (Real)Np;
|
|
|
+ Long i = (Long)(theta * Mt);
|
|
|
+ Long j = (Long)(phi * Mp);
|
|
|
+ Real x = theta * Mt - i;
|
|
|
+ Real y = phi * Mp - j;
|
|
|
+ Long elem_idx = i * Mp + j;
|
|
|
+
|
|
|
+ Vector<Real> Interp0(ORDER);
|
|
|
+ Vector<Real> Interp1(ORDER);
|
|
|
+ { // Set Interp0, Interp1
|
|
|
+ auto node = [&Mnodes] (Long i) {
|
|
|
+ return Mnodes[0][i];
|
|
|
+ };
|
|
|
+ for (Long i = 0; i < ORDER; i++) {
|
|
|
+ Real wt_x = 1, wt_y = 1;
|
|
|
+ for (Long j = 0; j < ORDER; j++) {
|
|
|
+ if (j != i) {
|
|
|
+ wt_x *= (x - node(j)) / (node(i) - node(j));
|
|
|
+ wt_y *= (y - node(j)) / (node(i) - node(j));
|
|
|
+ }
|
|
|
+ Interp0[i] = wt_x;
|
|
|
+ Interp1[i] = wt_y;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for (Long ii = 0; ii < ORDER; ii++) {
|
|
|
+ for (Long jj = 0; jj < ORDER; jj++) {
|
|
|
+ Long node_idx = jj * ORDER + ii;
|
|
|
+ for (Long k = 0; k < dof; k++) {
|
|
|
+ Xf[(k*Nt+t)*Np+p] += X[elem_idx*dof+k][node_idx] * Interp0[ii] * Interp1[jj];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return Xf;
|
|
|
+ };
|
|
|
+ auto grid2cheb = [] (const Vector<Real>& Xf, Long Nt, Long Np, Long Mt, Long Mp) {
|
|
|
+ Long dof = Xf.Dim() / (Nt*Np);
|
|
|
+ SCTL_ASSERT(Xf.Dim() == dof*Nt*Np);
|
|
|
+ Vector<ElemBasis> X(Mt*Mp*dof);
|
|
|
+ constexpr Integer INTERP_ORDER = 12;
|
|
|
+
|
|
|
+ for (Long tt = 0; tt < Mt; tt++) {
|
|
|
+ for (Long pp = 0; pp < Mp; pp++) {
|
|
|
+ for (Long t = 0; t < ORDER; t++) {
|
|
|
+ for (Long p = 0; p < ORDER; p++) {
|
|
|
+ Matrix<Real> Mnodes = Basis<Real,1,ORDER>::Nodes();
|
|
|
+ Real theta = (tt + Mnodes[0][t]) / Mt;
|
|
|
+ Real phi = (pp + Mnodes[0][p]) / Mp;
|
|
|
+ Long i = (Long)(theta * Nt);
|
|
|
+ Long j = (Long)(phi * Np);
|
|
|
+ Real x = theta * Nt - i;
|
|
|
+ Real y = phi * Np - j;
|
|
|
+
|
|
|
+ Vector<Real> Interp0(INTERP_ORDER);
|
|
|
+ Vector<Real> Interp1(INTERP_ORDER);
|
|
|
+ { // Set Interp0, Interp1
|
|
|
+ auto node = [] (Long i) {
|
|
|
+ return (Real)i - (INTERP_ORDER-1)/2;
|
|
|
+ };
|
|
|
+ for (Long i = 0; i < INTERP_ORDER; i++) {
|
|
|
+ Real wt_x = 1, wt_y = 1;
|
|
|
+ for (Long j = 0; j < INTERP_ORDER; j++) {
|
|
|
+ if (j != i) {
|
|
|
+ wt_x *= (x - node(j)) / (node(i) - node(j));
|
|
|
+ wt_y *= (y - node(j)) / (node(i) - node(j));
|
|
|
+ }
|
|
|
+ Interp0[i] = wt_x;
|
|
|
+ Interp1[i] = wt_y;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for (Long k = 0; k < dof; k++) {
|
|
|
+ Real X0 = 0;
|
|
|
+ for (Long ii = 0; ii < INTERP_ORDER; ii++) {
|
|
|
+ for (Long jj = 0; jj < INTERP_ORDER; jj++) {
|
|
|
+ Long idx_i = (i + ii-(INTERP_ORDER-1)/2 + Nt) % Nt;
|
|
|
+ Long idx_j = (j + jj-(INTERP_ORDER-1)/2 + Np) % Np;
|
|
|
+ X0 += Interp0[ii] * Interp1[jj] * Xf[(k*Nt+idx_i)*Np+idx_j];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ Long elem_idx = tt * Mp + pp;
|
|
|
+ Long node_idx = p * ORDER + t;
|
|
|
+ X[elem_idx*dof+k][node_idx] = X0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return X;
|
|
|
+ };
|
|
|
+
|
|
|
+ Long Nelem = S.GetElemList().NElem();
|
|
|
+ Vector<ElemBasis> Jt(Nelem*COORD_DIM), Jp(Nelem*COORD_DIM);
|
|
|
+ for (Long k = 0; k < S.Nsurf(); k++) {
|
|
|
+ Long Nt = S.NTor(k)*ORDER, Np = S.NPol(k)*ORDER;
|
|
|
+ const auto& X_ = S.GetElemList().ElemVector();
|
|
|
+ Vector<ElemBasis> X(S.NTor(k)*S.NPol(k)*COORD_DIM, (Iterator<ElemBasis>)X_.begin()+S.ElemDsp(k)*COORD_DIM, false);
|
|
|
+
|
|
|
+ biest::Surface<Real> SS(Nt, Np);
|
|
|
+ biest::SurfaceOp<Real> surf_op(comm, Nt, Np);
|
|
|
+ SS.Coord() = cheb2grid(X, S.NTor(k), S.NPol(k), Nt, Np);
|
|
|
+
|
|
|
+ Vector<Real> dX, d2X;
|
|
|
+ surf_op.Grad2D(dX, SS.Coord());
|
|
|
+ surf_op.Grad2D(d2X, dX);
|
|
|
+
|
|
|
+ sctl::Vector<Real> Jt_(COORD_DIM * Nt * Np);
|
|
|
+ sctl::Vector<Real> Jp_(COORD_DIM * Nt * Np);
|
|
|
+ { // Set Jt_, Jp_
|
|
|
+ Vector<Real> DivV, InvLapDivV, GradInvLapDivV;
|
|
|
+ for (sctl::Long i = 0; i < Nt*Np; i++) { // Set V
|
|
|
+ for (sctl::Long k =0; k < COORD_DIM; k++) {
|
|
|
+ Jt_[k * Nt*Np + i] = dX[(k*2+0) * Nt*Np + i];
|
|
|
+ Jp_[k * Nt*Np + i] = dX[(k*2+1) * Nt*Np + i];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ surf_op.SurfDiv(DivV, dX, Jt_);
|
|
|
+ surf_op.GradInvSurfLap(GradInvLapDivV, dX, d2X, DivV, gmres_tol * max_norm(Jt_) / max_norm(DivV), max_iter, 1.5);
|
|
|
+ Jt_ = Jt_ - GradInvLapDivV;
|
|
|
+
|
|
|
+ surf_op.SurfDiv(DivV, dX, Jp_);
|
|
|
+ surf_op.GradInvSurfLap(GradInvLapDivV, dX, d2X, DivV, gmres_tol * max_norm(Jp_) / max_norm(DivV), max_iter, 1.5);
|
|
|
+ Jp_ = Jp_ - GradInvLapDivV;
|
|
|
+ }
|
|
|
+ Vector<ElemBasis> Jt__(S.NTor(k)*S.NPol(k)*COORD_DIM, (Iterator<ElemBasis>)Jt.begin()+S.ElemDsp(k)*COORD_DIM, false);
|
|
|
+ Vector<ElemBasis> Jp__(S.NTor(k)*S.NPol(k)*COORD_DIM, (Iterator<ElemBasis>)Jp.begin()+S.ElemDsp(k)*COORD_DIM, false);
|
|
|
+ Jt__ = grid2cheb(Jt_, Nt, Np, S.NTor(k), S.NPol(k));
|
|
|
+ Jp__ = grid2cheb(Jp_, Nt, Np, S.NTor(k), S.NPol(k));
|
|
|
+ }
|
|
|
+
|
|
|
Vector<ElemBasis> normal, area_elem;
|
|
|
auto compute_dot_prod = [](const Vector<ElemBasis>& A, const Vector<ElemBasis>& B) {
|
|
|
const Long Nelem = A.Dim() / COORD_DIM;
|
|
@@ -2279,7 +2472,13 @@ template <class Real, Integer ORDER=10> class Stellarator {
|
|
|
S.quadrature_FxdU.template Setup<ElemBasis, ElemBasis>(S.GetElemList(), S.Laplace_FxdU, order_singular, order_direct, -1.0, comm);
|
|
|
S.quadrature_dUxF.template Setup<ElemBasis, ElemBasis>(S.GetElemList(), S.Laplace_dUxF, order_singular, order_direct, -1.0, comm);
|
|
|
|
|
|
- auto compute_B0 = [&S](const Real alpha) { // alpha/|r| \hat{\theta}
|
|
|
+ GenericKernel<BiotSavart3D> BiotSavart;
|
|
|
+ GenericKernel<BiotSavartGrad3D> BiotSavartGrad;
|
|
|
+ Quadrature<Real> quadrature_BS, quadrature_dBS;
|
|
|
+ quadrature_BS .template Setup<ElemBasis, ElemBasis>(S.GetElemList(), BiotSavart , order_singular, order_direct, -1.0, comm, -0.01 * pow<-2,Real>(ORDER));
|
|
|
+ quadrature_dBS.template Setup<ElemBasis, ElemBasis>(S.GetElemList(), BiotSavartGrad, order_singular, order_direct, -1.0, comm, -0.01 * pow<-2,Real>(ORDER));
|
|
|
+
|
|
|
+ auto compute_B0_deprecated = [&S](const Real alpha) { // alpha/|r| \hat{\theta}
|
|
|
const Vector<ElemBasis> X = S.GetElemList().ElemVector();
|
|
|
const Long Nelem = S.GetElemList().NElem();
|
|
|
const Long Nnodes = ElemBasis::Size();
|
|
@@ -2310,7 +2509,7 @@ template <class Real, Integer ORDER=10> class Stellarator {
|
|
|
}
|
|
|
return B0;
|
|
|
};
|
|
|
- auto compute_dB0 = [&S](const Real alpha) { // alpha/|r| \hat{\theta}
|
|
|
+ auto compute_dB0_deprecated = [&S](const Real alpha) { // alpha/|r| \hat{\theta}
|
|
|
const Vector<ElemBasis> X = S.GetElemList().ElemVector();
|
|
|
const Long Nelem = S.GetElemList().NElem();
|
|
|
const Long Nnodes = ElemBasis::Size();
|
|
@@ -2339,6 +2538,16 @@ template <class Real, Integer ORDER=10> class Stellarator {
|
|
|
}
|
|
|
return dB0;
|
|
|
};
|
|
|
+ auto compute_B0 = [&S, &Jp,&BiotSavart,&quadrature_BS](const Real alpha) {
|
|
|
+ Vector<ElemBasis> B0;
|
|
|
+ quadrature_BS.Eval(B0, S.GetElemList(), Jp, BiotSavart);
|
|
|
+ return B0*alpha;
|
|
|
+ };
|
|
|
+ auto compute_dB0 = [&S, &Jp,&BiotSavartGrad,&quadrature_dBS](const Real alpha) {
|
|
|
+ Vector<ElemBasis> dB0;
|
|
|
+ quadrature_dBS.Eval(dB0, S.GetElemList(), Jp, BiotSavartGrad);
|
|
|
+ return dB0*alpha;
|
|
|
+ };
|
|
|
auto compute_half_n_plus_dG = [&S, &normal](const Vector<ElemBasis>& sigma) { // B = n sigma/2 + dG[sigma]
|
|
|
const Long Nelem = S.GetElemList().NElem();
|
|
|
const Long Nnodes = ElemBasis::Size();
|
|
@@ -2531,18 +2740,10 @@ template <class Real, Integer ORDER=10> class Stellarator {
|
|
|
ElemBasis::Grad(dX, S.GetElemList().ElemVector());
|
|
|
for (Long i = 0; i < Nelem; i++) {
|
|
|
for (Long j = 0; j < Nnodes; j++) {
|
|
|
- Tensor<Real,true,COORD_DIM,2> dx;
|
|
|
- dx(0,0) = dX[i*COORD_DIM*2+0][j];
|
|
|
- dx(0,1) = dX[i*COORD_DIM*2+1][j];
|
|
|
- dx(1,0) = dX[i*COORD_DIM*2+2][j];
|
|
|
- dx(1,1) = dX[i*COORD_DIM*2+3][j];
|
|
|
- dx(2,0) = dX[i*COORD_DIM*2+4][j];
|
|
|
- dx(2,1) = dX[i*COORD_DIM*2+5][j];
|
|
|
-
|
|
|
Real s = 1 / (area_elem[i][j] * S.NtNp_[0]);
|
|
|
- for (Long k = 0; k < COORD_DIM; k++) {
|
|
|
- density[i*COORD_DIM+k][j] = dx(k,1) * s;
|
|
|
- }
|
|
|
+ density[i*COORD_DIM+0][j] = dX[i*COORD_DIM*2+1][j] * s;
|
|
|
+ density[i*COORD_DIM+1][j] = dX[i*COORD_DIM*2+3][j] * s;
|
|
|
+ density[i*COORD_DIM+2][j] = dX[i*COORD_DIM*2+5][j] * s;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -4168,855 +4369,6 @@ template <class Real, Integer ORDER=10> class Stellarator {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- static void test_Askham() {
|
|
|
- constexpr Integer order_singular = 15;
|
|
|
- constexpr Integer order_direct = 35;
|
|
|
- Comm comm = Comm::World();
|
|
|
- Profile::Enable(true);
|
|
|
-
|
|
|
- Stellarator<Real,ORDER> S;
|
|
|
- { // Init S
|
|
|
- Vector<Long> NtNp;
|
|
|
- NtNp.PushBack(20);
|
|
|
- NtNp.PushBack(4);
|
|
|
- S = Stellarator<Real,ORDER>(NtNp);
|
|
|
- }
|
|
|
-
|
|
|
- Vector<ElemBasis> normal, area_elem;
|
|
|
- auto compute_dot_prod = [](const Vector<ElemBasis>& A, const Vector<ElemBasis>& B) {
|
|
|
- const Long Nelem = A.Dim() / COORD_DIM;
|
|
|
- const Long Nnodes = ElemBasis::Size();
|
|
|
- SCTL_ASSERT(A.Dim() == Nelem * COORD_DIM);
|
|
|
- SCTL_ASSERT(B.Dim() == Nelem * COORD_DIM);
|
|
|
- Vector<ElemBasis> AdotB(Nelem);
|
|
|
- for (Long i = 0; i < Nelem; i++) {
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- Real a_dot_b = 0;
|
|
|
- a_dot_b += A[i*COORD_DIM+0][j]*B[i*COORD_DIM+0][j];
|
|
|
- a_dot_b += A[i*COORD_DIM+1][j]*B[i*COORD_DIM+1][j];
|
|
|
- a_dot_b += A[i*COORD_DIM+2][j]*B[i*COORD_DIM+2][j];
|
|
|
- AdotB[i][j] = a_dot_b;
|
|
|
- }
|
|
|
- }
|
|
|
- return AdotB;
|
|
|
- };
|
|
|
- auto compute_inner_prod = [&S, &area_elem](const Vector<ElemBasis>& A, const Vector<ElemBasis>& B) {
|
|
|
- const auto& quad_wts = ElemBasis::QuadWts();
|
|
|
- const Long Nelem = S.GetElemList().NElem();
|
|
|
- const Long Nnodes = ElemBasis::Size();
|
|
|
- const Long dof = B.Dim() / Nelem;
|
|
|
- Real sum = 0;
|
|
|
- for (Long i = 0; i < Nelem; i++) {
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- Real AdotB = 0;
|
|
|
- for (Long k = 0; k < dof; k++) {
|
|
|
- AdotB += A[i*dof+k][j] * B[i*dof+k][j];
|
|
|
- }
|
|
|
- sum += AdotB * area_elem[i][j] * quad_wts[j];
|
|
|
- }
|
|
|
- }
|
|
|
- return sum;
|
|
|
- };
|
|
|
- auto compute_norm_area_elem = [&S](Vector<ElemBasis>& normal, Vector<ElemBasis>& area_elem){ // Set normal, area_elem
|
|
|
- const Vector<ElemBasis> X = S.GetElemList().ElemVector();
|
|
|
- const Long Nelem = S.GetElemList().NElem();
|
|
|
- const Long Nnodes = ElemBasis::Size();
|
|
|
-
|
|
|
- Vector<ElemBasis> dX;
|
|
|
- ElemBasis::Grad(dX, X);
|
|
|
-
|
|
|
- area_elem.ReInit(Nelem);
|
|
|
- normal.ReInit(Nelem * COORD_DIM);
|
|
|
- for (Long i = 0; i < Nelem; i++) {
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- Tensor<Real,true,COORD_DIM> x, n;
|
|
|
- Tensor<Real,true,COORD_DIM,2> dx;
|
|
|
- x(0) = X[i*COORD_DIM+0][j];
|
|
|
- x(1) = X[i*COORD_DIM+1][j];
|
|
|
- x(2) = X[i*COORD_DIM+2][j];
|
|
|
-
|
|
|
- dx(0,0) = dX[i*COORD_DIM*2+0][j];
|
|
|
- dx(0,1) = dX[i*COORD_DIM*2+1][j];
|
|
|
- dx(1,0) = dX[i*COORD_DIM*2+2][j];
|
|
|
- dx(1,1) = dX[i*COORD_DIM*2+3][j];
|
|
|
- dx(2,0) = dX[i*COORD_DIM*2+4][j];
|
|
|
- dx(2,1) = dX[i*COORD_DIM*2+5][j];
|
|
|
-
|
|
|
- n(0) = dx(1,0) * dx(2,1) - dx(2,0) * dx(1,1);
|
|
|
- n(1) = dx(2,0) * dx(0,1) - dx(0,0) * dx(2,1);
|
|
|
- n(2) = dx(0,0) * dx(1,1) - dx(1,0) * dx(0,1);
|
|
|
- Real area_elem_ = sqrt<Real>(n(0)*n(0) + n(1)*n(1) + n(2)*n(2));
|
|
|
- Real ooae = 1 / area_elem_;
|
|
|
- n(0) *= ooae;
|
|
|
- n(1) *= ooae;
|
|
|
- n(2) *= ooae;
|
|
|
-
|
|
|
- normal[i*COORD_DIM+0][j] = n(0);
|
|
|
- normal[i*COORD_DIM+1][j] = n(1);
|
|
|
- normal[i*COORD_DIM+2][j] = n(2);
|
|
|
- area_elem[i][j] = area_elem_;
|
|
|
- }
|
|
|
- }
|
|
|
- };
|
|
|
- compute_norm_area_elem(normal, area_elem);
|
|
|
-
|
|
|
- S.quadrature_FxU .template Setup<ElemBasis, ElemBasis>(S.GetElemList(), S.Laplace_FxU , order_singular, order_direct, -1.0, comm);
|
|
|
- S.quadrature_DxU .template Setup<ElemBasis, ElemBasis>(S.GetElemList(), S.Laplace_DxU , order_singular, order_direct, -1.0, comm);
|
|
|
- S.quadrature_FxdU.template Setup<ElemBasis, ElemBasis>(S.GetElemList(), S.Laplace_FxdU, order_singular, order_direct, -1.0, comm);
|
|
|
- S.quadrature_dUxF.template Setup<ElemBasis, ElemBasis>(S.GetElemList(), S.Laplace_dUxF, order_singular, order_direct, -1.0, comm);
|
|
|
-
|
|
|
- auto compute_poloidal_circulation = [&S] (const Vector<ElemBasis>& B) {
|
|
|
- const Vector<ElemBasis> X = S.GetElemList().ElemVector();
|
|
|
- const Long Nelem = S.GetElemList().NElem();
|
|
|
- const Long Nnodes = ElemBasis::Size();
|
|
|
- const auto& quad_wts = Basis<Real,1,ORDER>::QuadWts();
|
|
|
-
|
|
|
- Vector<ElemBasis> dX;
|
|
|
- ElemBasis::Grad(dX, X);
|
|
|
- const Long Nt = 40;
|
|
|
- const Long Np = 8;
|
|
|
- for (Long t = 0; t < Nt; t++) {
|
|
|
- for (Long j = 0; j < ORDER; j++) {
|
|
|
- Real sum = 0;
|
|
|
- for (Long p = 0; p < Np; p++) {
|
|
|
- for (Long i = 0; i < ORDER; i++) {
|
|
|
- Long elem_idx = t*Np+p;
|
|
|
- Long node_idx = i*ORDER+j;
|
|
|
-
|
|
|
- Tensor<Real,true,COORD_DIM,2> dx;
|
|
|
- dx(0,0) = dX[elem_idx*COORD_DIM*2+0][node_idx];
|
|
|
- dx(0,1) = dX[elem_idx*COORD_DIM*2+1][node_idx];
|
|
|
- dx(1,0) = dX[elem_idx*COORD_DIM*2+2][node_idx];
|
|
|
- dx(1,1) = dX[elem_idx*COORD_DIM*2+3][node_idx];
|
|
|
- dx(2,0) = dX[elem_idx*COORD_DIM*2+4][node_idx];
|
|
|
- dx(2,1) = dX[elem_idx*COORD_DIM*2+5][node_idx];
|
|
|
-
|
|
|
- Tensor<Real,true,COORD_DIM> b;
|
|
|
- b(0) = B[elem_idx*COORD_DIM+0][node_idx];
|
|
|
- b(1) = B[elem_idx*COORD_DIM+1][node_idx];
|
|
|
- b(2) = B[elem_idx*COORD_DIM+2][node_idx];
|
|
|
-
|
|
|
- sum += (b(0)*dx(0,1) + b(1)*dx(1,1) + b(2)*dx(2,1)) * quad_wts[i];
|
|
|
- }
|
|
|
- }
|
|
|
- std::cout<<sum<<' ';
|
|
|
- }
|
|
|
- }
|
|
|
- std::cout<<'\n';
|
|
|
- };
|
|
|
- auto compute_toroidal_circulation = [&S] (const Vector<ElemBasis>& B) {
|
|
|
- const Vector<ElemBasis> X = S.GetElemList().ElemVector();
|
|
|
- const Long Nelem = S.GetElemList().NElem();
|
|
|
- const Long Nnodes = ElemBasis::Size();
|
|
|
- const auto& quad_wts = Basis<Real,1,ORDER>::QuadWts();
|
|
|
-
|
|
|
- Vector<ElemBasis> dX;
|
|
|
- ElemBasis::Grad(dX, X);
|
|
|
- const Long Nt = 40;
|
|
|
- const Long Np = 8;
|
|
|
- for (Long p = 0; p < Np; p++) {
|
|
|
- for (Long i = 0; i < ORDER; i++) {
|
|
|
- Real sum = 0;
|
|
|
- for (Long t = 0; t < Nt; t++) {
|
|
|
- for (Long j = 0; j < ORDER; j++) {
|
|
|
- Long elem_idx = t*Np+p;
|
|
|
- Long node_idx = i*ORDER+j;
|
|
|
-
|
|
|
- Tensor<Real,true,COORD_DIM,2> dx;
|
|
|
- dx(0,0) = dX[elem_idx*COORD_DIM*2+0][node_idx];
|
|
|
- dx(0,1) = dX[elem_idx*COORD_DIM*2+1][node_idx];
|
|
|
- dx(1,0) = dX[elem_idx*COORD_DIM*2+2][node_idx];
|
|
|
- dx(1,1) = dX[elem_idx*COORD_DIM*2+3][node_idx];
|
|
|
- dx(2,0) = dX[elem_idx*COORD_DIM*2+4][node_idx];
|
|
|
- dx(2,1) = dX[elem_idx*COORD_DIM*2+5][node_idx];
|
|
|
-
|
|
|
- Tensor<Real,true,COORD_DIM> b;
|
|
|
- b(0) = B[elem_idx*COORD_DIM+0][node_idx];
|
|
|
- b(1) = B[elem_idx*COORD_DIM+1][node_idx];
|
|
|
- b(2) = B[elem_idx*COORD_DIM+2][node_idx];
|
|
|
-
|
|
|
- sum += (b(0)*dx(0,0) + b(1)*dx(1,0) + b(2)*dx(2,0)) * quad_wts[j];
|
|
|
- }
|
|
|
- }
|
|
|
- std::cout<<sum<<' ';
|
|
|
- }
|
|
|
- }
|
|
|
- std::cout<<'\n';
|
|
|
- };
|
|
|
-
|
|
|
- auto compute_poloidal_circulation_ = [&S,&area_elem] (const Vector<ElemBasis>& B) {
|
|
|
- const Vector<ElemBasis> X = S.GetElemList().ElemVector();
|
|
|
- const Long Nelem = S.GetElemList().NElem();
|
|
|
- const Long Nnodes = ElemBasis::Size();
|
|
|
- const auto& quad_wts = ElemBasis::QuadWts();
|
|
|
-
|
|
|
- Vector<ElemBasis> dX;
|
|
|
- ElemBasis::Grad(dX, X);
|
|
|
- Real sum = 0;
|
|
|
- for (Long i = 0; i < Nelem; i++) {
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- Tensor<Real,true,COORD_DIM,2> dx;
|
|
|
- dx(0,0) = dX[i*COORD_DIM*2+0][j];
|
|
|
- dx(0,1) = dX[i*COORD_DIM*2+1][j];
|
|
|
- dx(1,0) = dX[i*COORD_DIM*2+2][j];
|
|
|
- dx(1,1) = dX[i*COORD_DIM*2+3][j];
|
|
|
- dx(2,0) = dX[i*COORD_DIM*2+4][j];
|
|
|
- dx(2,1) = dX[i*COORD_DIM*2+5][j];
|
|
|
-
|
|
|
- Tensor<Real,true,COORD_DIM> b;
|
|
|
- b(0) = B[i*COORD_DIM+0][j];
|
|
|
- b(1) = B[i*COORD_DIM+1][j];
|
|
|
- b(2) = B[i*COORD_DIM+2][j];
|
|
|
-
|
|
|
- Real s = 1/area_elem[i][j];
|
|
|
- sum += (b(0)*dx(0,1) + b(1)*dx(1,1) + b(2)*dx(2,1)) * s * area_elem[i][j] * quad_wts[j];
|
|
|
- }
|
|
|
- }
|
|
|
- return sum;
|
|
|
- };
|
|
|
- auto compute_toroidal_circulation_ = [&S,&area_elem] (const Vector<ElemBasis>& B) {
|
|
|
- const Vector<ElemBasis> X = S.GetElemList().ElemVector();
|
|
|
- const Long Nelem = S.GetElemList().NElem();
|
|
|
- const Long Nnodes = ElemBasis::Size();
|
|
|
- const auto& quad_wts = ElemBasis::QuadWts();
|
|
|
-
|
|
|
- Vector<ElemBasis> dX;
|
|
|
- ElemBasis::Grad(dX, X);
|
|
|
- Real sum = 0;
|
|
|
- for (Long i = 0; i < Nelem; i++) {
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- Tensor<Real,true,COORD_DIM,2> dx;
|
|
|
- dx(0,0) = dX[i*COORD_DIM*2+0][j];
|
|
|
- dx(0,1) = dX[i*COORD_DIM*2+1][j];
|
|
|
- dx(1,0) = dX[i*COORD_DIM*2+2][j];
|
|
|
- dx(1,1) = dX[i*COORD_DIM*2+3][j];
|
|
|
- dx(2,0) = dX[i*COORD_DIM*2+4][j];
|
|
|
- dx(2,1) = dX[i*COORD_DIM*2+5][j];
|
|
|
-
|
|
|
- Tensor<Real,true,COORD_DIM> b;
|
|
|
- b(0) = B[i*COORD_DIM+0][j];
|
|
|
- b(1) = B[i*COORD_DIM+1][j];
|
|
|
- b(2) = B[i*COORD_DIM+2][j];
|
|
|
-
|
|
|
- Real s = 1/area_elem[i][j];
|
|
|
- sum += (b(0)*dx(0,0) + b(1)*dx(1,0) + b(2)*dx(2,0)) * s * area_elem[i][j] * quad_wts[j];
|
|
|
- }
|
|
|
- }
|
|
|
- return sum;
|
|
|
- };
|
|
|
-
|
|
|
- auto compute_grad = [&S] (const Vector<ElemBasis>& F) {
|
|
|
- const Long Nelem = S.GetElemList().NElem();
|
|
|
- const Long Nnodes = ElemBasis::Size();
|
|
|
-
|
|
|
- Vector<ElemBasis> du_dX(Nelem*COORD_DIM*2);
|
|
|
- { // Set du_dX
|
|
|
- Vector<ElemBasis> dX;
|
|
|
- ElemBasis::Grad(dX, S.GetElemList().ElemVector());
|
|
|
-
|
|
|
- auto inv2x2 = [](Tensor<Real, true, 2, 2> M) {
|
|
|
- Tensor<Real, true, 2, 2> Mout;
|
|
|
- Real oodet = 1 / (M(0,0) * M(1,1) - M(0,1) * M(1,0));
|
|
|
- Mout(0,0) = M(1,1) * oodet;
|
|
|
- Mout(0,1) = -M(0,1) * oodet;
|
|
|
- Mout(1,0) = -M(1,0) * oodet;
|
|
|
- Mout(1,1) = M(0,0) * oodet;
|
|
|
- return Mout;
|
|
|
- };
|
|
|
- for (Long i = 0; i < Nelem; i++) {
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- Tensor<Real, true, 3, 2> dX_du;
|
|
|
- dX_du(0,0) = dX[(i*COORD_DIM+0)*2+0][j];
|
|
|
- dX_du(1,0) = dX[(i*COORD_DIM+1)*2+0][j];
|
|
|
- dX_du(2,0) = dX[(i*COORD_DIM+2)*2+0][j];
|
|
|
- dX_du(0,1) = dX[(i*COORD_DIM+0)*2+1][j];
|
|
|
- dX_du(1,1) = dX[(i*COORD_DIM+1)*2+1][j];
|
|
|
- dX_du(2,1) = dX[(i*COORD_DIM+2)*2+1][j];
|
|
|
-
|
|
|
- Tensor<Real, true, 2, 2> G; // = dX_du.Transpose() * dX_du;
|
|
|
- G(0,0) = dX_du(0,0) * dX_du(0,0) + dX_du(1,0) * dX_du(1,0) + dX_du(2,0) * dX_du(2,0);
|
|
|
- G(0,1) = dX_du(0,0) * dX_du(0,1) + dX_du(1,0) * dX_du(1,1) + dX_du(2,0) * dX_du(2,1);
|
|
|
- G(1,0) = dX_du(0,1) * dX_du(0,0) + dX_du(1,1) * dX_du(1,0) + dX_du(2,1) * dX_du(2,0);
|
|
|
- G(1,1) = dX_du(0,1) * dX_du(0,1) + dX_du(1,1) * dX_du(1,1) + dX_du(2,1) * dX_du(2,1);
|
|
|
-
|
|
|
- Tensor<Real, true, 2, 2> Ginv = inv2x2(G);
|
|
|
- du_dX[(i*COORD_DIM+0)*2+0][j] = Ginv(0,0) * dX_du(0,0) + Ginv(0,1) * dX_du(0,1);
|
|
|
- du_dX[(i*COORD_DIM+1)*2+0][j] = Ginv(0,0) * dX_du(1,0) + Ginv(0,1) * dX_du(1,1);
|
|
|
- du_dX[(i*COORD_DIM+2)*2+0][j] = Ginv(0,0) * dX_du(2,0) + Ginv(0,1) * dX_du(2,1);
|
|
|
- du_dX[(i*COORD_DIM+0)*2+1][j] = Ginv(1,0) * dX_du(0,0) + Ginv(1,1) * dX_du(0,1);
|
|
|
- du_dX[(i*COORD_DIM+1)*2+1][j] = Ginv(1,0) * dX_du(1,0) + Ginv(1,1) * dX_du(1,1);
|
|
|
- du_dX[(i*COORD_DIM+2)*2+1][j] = Ginv(1,0) * dX_du(2,0) + Ginv(1,1) * dX_du(2,1);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- Vector<ElemBasis> dF;
|
|
|
- ElemBasis::Grad(dF, F);
|
|
|
-
|
|
|
- Long dof = F.Dim() / Nelem;
|
|
|
- SCTL_ASSERT(F.Dim() == Nelem * dof);
|
|
|
- Vector<ElemBasis> gradF(Nelem*dof*3);
|
|
|
- for (Long i = 0; i < Nelem; i++) {
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- for (Long k = 0; k < dof; k++) {
|
|
|
- gradF[(i*dof+k)*COORD_DIM+0][j] = dF[(i*dof+k)*2+0][j]*du_dX[(i*COORD_DIM+0)*2+0][j] + dF[(i*dof+k)*2+1][j]*du_dX[(i*COORD_DIM+0)*2+1][j];
|
|
|
- gradF[(i*dof+k)*COORD_DIM+1][j] = dF[(i*dof+k)*2+0][j]*du_dX[(i*COORD_DIM+1)*2+0][j] + dF[(i*dof+k)*2+1][j]*du_dX[(i*COORD_DIM+1)*2+1][j];
|
|
|
- gradF[(i*dof+k)*COORD_DIM+2][j] = dF[(i*dof+k)*2+0][j]*du_dX[(i*COORD_DIM+2)*2+0][j] + dF[(i*dof+k)*2+1][j]*du_dX[(i*COORD_DIM+2)*2+1][j];
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- return gradF;
|
|
|
- };
|
|
|
- auto compute_grad_adj = [&S,&area_elem] (const Vector<ElemBasis>& V) {
|
|
|
- const Long Nelem = S.GetElemList().NElem();
|
|
|
- const Long Nnodes = ElemBasis::Size();
|
|
|
-
|
|
|
- Vector<ElemBasis> du_dX(Nelem*COORD_DIM*2);
|
|
|
- { // Set du_dX
|
|
|
- Vector<ElemBasis> dX;
|
|
|
- ElemBasis::Grad(dX, S.GetElemList().ElemVector());
|
|
|
-
|
|
|
- auto inv2x2 = [](Tensor<Real, true, 2, 2> M) {
|
|
|
- Tensor<Real, true, 2, 2> Mout;
|
|
|
- Real oodet = 1 / (M(0,0) * M(1,1) - M(0,1) * M(1,0));
|
|
|
- Mout(0,0) = M(1,1) * oodet;
|
|
|
- Mout(0,1) = -M(0,1) * oodet;
|
|
|
- Mout(1,0) = -M(1,0) * oodet;
|
|
|
- Mout(1,1) = M(0,0) * oodet;
|
|
|
- return Mout;
|
|
|
- };
|
|
|
- for (Long i = 0; i < Nelem; i++) {
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- Tensor<Real, true, 3, 2> dX_du;
|
|
|
- dX_du(0,0) = dX[(i*COORD_DIM+0)*2+0][j];
|
|
|
- dX_du(1,0) = dX[(i*COORD_DIM+1)*2+0][j];
|
|
|
- dX_du(2,0) = dX[(i*COORD_DIM+2)*2+0][j];
|
|
|
- dX_du(0,1) = dX[(i*COORD_DIM+0)*2+1][j];
|
|
|
- dX_du(1,1) = dX[(i*COORD_DIM+1)*2+1][j];
|
|
|
- dX_du(2,1) = dX[(i*COORD_DIM+2)*2+1][j];
|
|
|
-
|
|
|
- Tensor<Real, true, 2, 2> G; // = dX_du.Transpose() * dX_du;
|
|
|
- G(0,0) = dX_du(0,0) * dX_du(0,0) + dX_du(1,0) * dX_du(1,0) + dX_du(2,0) * dX_du(2,0);
|
|
|
- G(0,1) = dX_du(0,0) * dX_du(0,1) + dX_du(1,0) * dX_du(1,1) + dX_du(2,0) * dX_du(2,1);
|
|
|
- G(1,0) = dX_du(0,1) * dX_du(0,0) + dX_du(1,1) * dX_du(1,0) + dX_du(2,1) * dX_du(2,0);
|
|
|
- G(1,1) = dX_du(0,1) * dX_du(0,1) + dX_du(1,1) * dX_du(1,1) + dX_du(2,1) * dX_du(2,1);
|
|
|
-
|
|
|
- Tensor<Real, true, 2, 2> Ginv = inv2x2(G);
|
|
|
- du_dX[(i*COORD_DIM+0)*2+0][j] = Ginv(0,0) * dX_du(0,0) + Ginv(0,1) * dX_du(0,1);
|
|
|
- du_dX[(i*COORD_DIM+1)*2+0][j] = Ginv(0,0) * dX_du(1,0) + Ginv(0,1) * dX_du(1,1);
|
|
|
- du_dX[(i*COORD_DIM+2)*2+0][j] = Ginv(0,0) * dX_du(2,0) + Ginv(0,1) * dX_du(2,1);
|
|
|
- du_dX[(i*COORD_DIM+0)*2+1][j] = Ginv(1,0) * dX_du(0,0) + Ginv(1,1) * dX_du(0,1);
|
|
|
- du_dX[(i*COORD_DIM+1)*2+1][j] = Ginv(1,0) * dX_du(1,0) + Ginv(1,1) * dX_du(1,1);
|
|
|
- du_dX[(i*COORD_DIM+2)*2+1][j] = Ginv(1,0) * dX_du(2,0) + Ginv(1,1) * dX_du(2,1);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- Vector<ElemBasis> dudX_V(Nelem*2);
|
|
|
- for (Long i = 0; i < Nelem; i++) {
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- dudX_V[i*2+0][j] = 0;
|
|
|
- dudX_V[i*2+1][j] = 0;
|
|
|
-
|
|
|
- dudX_V[i*2+0][j] += du_dX[(i*COORD_DIM+0)*2+0][j] * V[i*COORD_DIM+0][j];
|
|
|
- dudX_V[i*2+0][j] += du_dX[(i*COORD_DIM+1)*2+0][j] * V[i*COORD_DIM+1][j];
|
|
|
- dudX_V[i*2+0][j] += du_dX[(i*COORD_DIM+2)*2+0][j] * V[i*COORD_DIM+2][j];
|
|
|
-
|
|
|
- dudX_V[i*2+1][j] += du_dX[(i*COORD_DIM+0)*2+1][j] * V[i*COORD_DIM+0][j];
|
|
|
- dudX_V[i*2+1][j] += du_dX[(i*COORD_DIM+1)*2+1][j] * V[i*COORD_DIM+1][j];
|
|
|
- dudX_V[i*2+1][j] += du_dX[(i*COORD_DIM+2)*2+1][j] * V[i*COORD_DIM+2][j];
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- Vector<ElemBasis> eye(Nnodes), Mgrad;
|
|
|
- eye = 0;
|
|
|
- for (Long i = 0; i < Nnodes; i++) eye[i][i] = 1;
|
|
|
- ElemBasis::Grad(Mgrad, eye);
|
|
|
-
|
|
|
- Vector<ElemBasis> grad_adj_V(Nelem);
|
|
|
- const auto& quad_wts = ElemBasis::QuadWts();
|
|
|
- for (Long i = 0; i < Nelem; i++) {
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- Real sum = 0;
|
|
|
- for (Long k = 0; k < Nnodes; k++) {
|
|
|
- sum += Mgrad[j*2+0][k] * dudX_V[i*2+0][k] * (area_elem[i][k] * quad_wts[k]) / (quad_wts[j] * area_elem[i][j]);
|
|
|
- sum += Mgrad[j*2+1][k] * dudX_V[i*2+1][k] * (area_elem[i][k] * quad_wts[k]) / (quad_wts[j] * area_elem[i][j]);
|
|
|
- }
|
|
|
- grad_adj_V[i][j] = sum;
|
|
|
- }
|
|
|
- }
|
|
|
- return grad_adj_V;
|
|
|
- };
|
|
|
- auto compute_div = [&S] (const Vector<ElemBasis>& F) {
|
|
|
- const Long Nelem = S.GetElemList().NElem();
|
|
|
- const Long Nnodes = ElemBasis::Size();
|
|
|
- SCTL_ASSERT(F.Dim() == Nelem*COORD_DIM);
|
|
|
-
|
|
|
- Vector<ElemBasis> du_dX(Nelem*COORD_DIM*2);
|
|
|
- { // Set du_dX
|
|
|
- Vector<ElemBasis> dX;
|
|
|
- ElemBasis::Grad(dX, S.GetElemList().ElemVector());
|
|
|
-
|
|
|
- auto inv2x2 = [](Tensor<Real, true, 2, 2> M) {
|
|
|
- Tensor<Real, true, 2, 2> Mout;
|
|
|
- Real oodet = 1 / (M(0,0) * M(1,1) - M(0,1) * M(1,0));
|
|
|
- Mout(0,0) = M(1,1) * oodet;
|
|
|
- Mout(0,1) = -M(0,1) * oodet;
|
|
|
- Mout(1,0) = -M(1,0) * oodet;
|
|
|
- Mout(1,1) = M(0,0) * oodet;
|
|
|
- return Mout;
|
|
|
- };
|
|
|
- for (Long i = 0; i < Nelem; i++) {
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- Tensor<Real, true, 3, 2> dX_du;
|
|
|
- dX_du(0,0) = dX[(i*COORD_DIM+0)*2+0][j];
|
|
|
- dX_du(1,0) = dX[(i*COORD_DIM+1)*2+0][j];
|
|
|
- dX_du(2,0) = dX[(i*COORD_DIM+2)*2+0][j];
|
|
|
- dX_du(0,1) = dX[(i*COORD_DIM+0)*2+1][j];
|
|
|
- dX_du(1,1) = dX[(i*COORD_DIM+1)*2+1][j];
|
|
|
- dX_du(2,1) = dX[(i*COORD_DIM+2)*2+1][j];
|
|
|
-
|
|
|
- Tensor<Real, true, 2, 2> G; // = dX_du.Transpose() * dX_du;
|
|
|
- G(0,0) = dX_du(0,0) * dX_du(0,0) + dX_du(1,0) * dX_du(1,0) + dX_du(2,0) * dX_du(2,0);
|
|
|
- G(0,1) = dX_du(0,0) * dX_du(0,1) + dX_du(1,0) * dX_du(1,1) + dX_du(2,0) * dX_du(2,1);
|
|
|
- G(1,0) = dX_du(0,1) * dX_du(0,0) + dX_du(1,1) * dX_du(1,0) + dX_du(2,1) * dX_du(2,0);
|
|
|
- G(1,1) = dX_du(0,1) * dX_du(0,1) + dX_du(1,1) * dX_du(1,1) + dX_du(2,1) * dX_du(2,1);
|
|
|
-
|
|
|
- Tensor<Real, true, 2, 2> Ginv = inv2x2(G);
|
|
|
- du_dX[(i*COORD_DIM+0)*2+0][j] = Ginv(0,0) * dX_du(0,0) + Ginv(0,1) * dX_du(0,1);
|
|
|
- du_dX[(i*COORD_DIM+1)*2+0][j] = Ginv(0,0) * dX_du(1,0) + Ginv(0,1) * dX_du(1,1);
|
|
|
- du_dX[(i*COORD_DIM+2)*2+0][j] = Ginv(0,0) * dX_du(2,0) + Ginv(0,1) * dX_du(2,1);
|
|
|
- du_dX[(i*COORD_DIM+0)*2+1][j] = Ginv(1,0) * dX_du(0,0) + Ginv(1,1) * dX_du(0,1);
|
|
|
- du_dX[(i*COORD_DIM+1)*2+1][j] = Ginv(1,0) * dX_du(1,0) + Ginv(1,1) * dX_du(1,1);
|
|
|
- du_dX[(i*COORD_DIM+2)*2+1][j] = Ginv(1,0) * dX_du(2,0) + Ginv(1,1) * dX_du(2,1);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- Vector<ElemBasis> dF;
|
|
|
- ElemBasis::Grad(dF, F);
|
|
|
-
|
|
|
- Vector<ElemBasis> divF(Nelem);
|
|
|
- for (Long i = 0; i < Nelem; i++) {
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- Real divF_ = 0;
|
|
|
- divF_ += dF[(i*COORD_DIM+0)*2+0][j]*du_dX[(i*COORD_DIM+0)*2+0][j] + dF[(i*COORD_DIM+0)*2+1][j]*du_dX[(i*COORD_DIM+0)*2+1][j];
|
|
|
- divF_ += dF[(i*COORD_DIM+1)*2+0][j]*du_dX[(i*COORD_DIM+1)*2+0][j] + dF[(i*COORD_DIM+1)*2+1][j]*du_dX[(i*COORD_DIM+1)*2+1][j];
|
|
|
- divF_ += dF[(i*COORD_DIM+2)*2+0][j]*du_dX[(i*COORD_DIM+2)*2+0][j] + dF[(i*COORD_DIM+2)*2+1][j]*du_dX[(i*COORD_DIM+2)*2+1][j];
|
|
|
- divF[i][j] = divF_;
|
|
|
- }
|
|
|
- }
|
|
|
- return divF;
|
|
|
- };
|
|
|
-
|
|
|
- auto compute_B0 = [&S](const Real alpha) { // alpha/|r| \hat{\theta}
|
|
|
- const Vector<ElemBasis> X = S.GetElemList().ElemVector();
|
|
|
- const Long Nelem = S.GetElemList().NElem();
|
|
|
- const Long Nnodes = ElemBasis::Size();
|
|
|
-
|
|
|
- Vector<ElemBasis> B0(Nelem * COORD_DIM);
|
|
|
- for (Long i = 0; i < Nelem; i++) {
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- Tensor<Real,true,COORD_DIM> x, b0, axis;
|
|
|
- x(0) = X[i*COORD_DIM+0][j];
|
|
|
- x(1) = X[i*COORD_DIM+1][j];
|
|
|
- x(2) = X[i*COORD_DIM+2][j];
|
|
|
-
|
|
|
- axis(0) = 0;
|
|
|
- axis(1) = 0;
|
|
|
- axis(2) = 1;
|
|
|
- b0(0) = axis(1) * x(2) - axis(2) * x(1);
|
|
|
- b0(1) = axis(2) * x(0) - axis(0) * x(2);
|
|
|
- b0(2) = axis(0) * x(1) - axis(1) * x(0);
|
|
|
- Real scale = 1 / (b0(0)*b0(0) + b0(1)*b0(1) + b0(2)*b0(2));
|
|
|
- b0(0) *= scale;
|
|
|
- b0(1) *= scale;
|
|
|
- b0(2) *= scale;
|
|
|
-
|
|
|
- B0[i*COORD_DIM+0][j] = alpha * b0(0);
|
|
|
- B0[i*COORD_DIM+1][j] = alpha * b0(1);
|
|
|
- B0[i*COORD_DIM+2][j] = alpha * b0(2);
|
|
|
- }
|
|
|
- }
|
|
|
- return B0;
|
|
|
- };
|
|
|
- auto compute_dB0 = [&S](const Real alpha) { // alpha/|r| \hat{\theta}
|
|
|
- const Vector<ElemBasis> X = S.GetElemList().ElemVector();
|
|
|
- const Long Nelem = S.GetElemList().NElem();
|
|
|
- const Long Nnodes = ElemBasis::Size();
|
|
|
-
|
|
|
- Vector<ElemBasis> dB0(Nelem * COORD_DIM * COORD_DIM);
|
|
|
- for (Long i = 0; i < Nelem; i++) {
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- Tensor<Real,true,COORD_DIM> x;
|
|
|
- x(0) = X[i*COORD_DIM+0][j];
|
|
|
- x(1) = X[i*COORD_DIM+1][j];
|
|
|
- x(2) = X[i*COORD_DIM+2][j];
|
|
|
- Real R2inv = 1 / (x(0)*x(0) + x(1)*x(1));
|
|
|
-
|
|
|
- dB0[(i*COORD_DIM+0)*COORD_DIM+0][j] = alpha * (2*x(0)*x(1) * R2inv*R2inv);
|
|
|
- dB0[(i*COORD_DIM+0)*COORD_DIM+1][j] = alpha * (-R2inv + 2*x(1)*x(1) * R2inv*R2inv);
|
|
|
- dB0[(i*COORD_DIM+0)*COORD_DIM+2][j] = 0;
|
|
|
-
|
|
|
- dB0[(i*COORD_DIM+1)*COORD_DIM+0][j] = alpha * (R2inv - 2*x(0)*x(0) * R2inv*R2inv);
|
|
|
- dB0[(i*COORD_DIM+1)*COORD_DIM+1][j] = alpha * (-2*x(0)*x(1) * R2inv*R2inv);
|
|
|
- dB0[(i*COORD_DIM+1)*COORD_DIM+2][j] = 0;
|
|
|
-
|
|
|
- dB0[(i*COORD_DIM+2)*COORD_DIM+0][j] = 0;
|
|
|
- dB0[(i*COORD_DIM+2)*COORD_DIM+1][j] = 0;
|
|
|
- dB0[(i*COORD_DIM+2)*COORD_DIM+2][j] = 0;
|
|
|
- }
|
|
|
- }
|
|
|
- return dB0;
|
|
|
- };
|
|
|
- auto compute_half_n_plus_dG = [&S, &normal](const Vector<ElemBasis>& sigma) { // B = n sigma/2 + dG[sigma]
|
|
|
- const Long Nelem = S.GetElemList().NElem();
|
|
|
- const Long Nnodes = ElemBasis::Size();
|
|
|
-
|
|
|
- Vector<ElemBasis> B;
|
|
|
- S.quadrature_FxdU.Eval(B, S.GetElemList(), sigma, S.Laplace_FxdU);
|
|
|
- for (Long i = 0; i < Nelem; i++) {
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- for (Long k = 0; k < COORD_DIM; k++) {
|
|
|
- B[i*COORD_DIM+k][j] -= 0.5*sigma[i][j]*normal[i*COORD_DIM+k][j];
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- return B;
|
|
|
- };
|
|
|
-
|
|
|
- auto compute_A11 = [&S,&normal,&compute_half_n_plus_dG,&compute_dot_prod](Vector<Real>& B_dot_n, const Vector<Real>& sigma) {
|
|
|
- const Long Nelem = S.GetElemList().NElem();
|
|
|
- const Long Nnodes = ElemBasis::Size();
|
|
|
- B_dot_n.ReInit(Nelem * Nnodes);
|
|
|
- Vector<ElemBasis> sigma_(Nelem);
|
|
|
- for (Long i = 0; i < Nelem; i++) {
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- sigma_[i][j] = sigma[i*Nnodes+j];
|
|
|
- }
|
|
|
- }
|
|
|
- Vector<ElemBasis> B_dot_n_ = compute_dot_prod(normal, compute_half_n_plus_dG(sigma_));
|
|
|
- for (Long i = 0; i < Nelem; i++) {
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- B_dot_n[i*Nnodes+j] = B_dot_n_[i][j];
|
|
|
- }
|
|
|
- }
|
|
|
- };
|
|
|
- auto compute_A12 = [&S,&normal,&compute_dot_prod,&compute_B0](Vector<Real>& B_dot_n, const Real alpha) {
|
|
|
- const Long Nelem = S.GetElemList().NElem();
|
|
|
- const Long Nnodes = ElemBasis::Size();
|
|
|
- B_dot_n.ReInit(Nelem * Nnodes);
|
|
|
- Vector<ElemBasis> B_dot_n_ = compute_dot_prod(normal, compute_B0(alpha));
|
|
|
- for (Long i = 0; i < Nelem; i++) {
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- B_dot_n[i*Nnodes+j] = B_dot_n_[i][j];
|
|
|
- }
|
|
|
- }
|
|
|
- };
|
|
|
- auto compute_A21 = [&S,&normal,&compute_half_n_plus_dG,&compute_poloidal_circulation_](const Vector<Real>& sigma) {
|
|
|
- const Long Nelem = S.GetElemList().NElem();
|
|
|
- const Long Nnodes = ElemBasis::Size();
|
|
|
-
|
|
|
- Vector<ElemBasis> sigma_(Nelem);
|
|
|
- for (Long i = 0; i < Nelem; i++) {
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- sigma_[i][j] = sigma[i*Nnodes+j];
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (0) { // alternate implementation
|
|
|
- //Vector<ElemBasis> A21_(Nelem);
|
|
|
- //Vector<Real> A21(Nelem*Nnodes);
|
|
|
- //compute_A21adj(A21, 1);
|
|
|
- //for (Long i = 0; i < Nelem; i++) {
|
|
|
- // for (Long j = 0; j < Nnodes; j++) {
|
|
|
- // A21_[i][j] = A21[i*Nnodes+j];
|
|
|
- // }
|
|
|
- //}
|
|
|
- //return compute_inner_prod(A21_, sigma_);
|
|
|
- }
|
|
|
- Vector<ElemBasis> B = compute_half_n_plus_dG(sigma_);
|
|
|
-
|
|
|
- Vector<ElemBasis> J(Nelem * COORD_DIM);
|
|
|
- for (Long i = 0; i < Nelem; i++) { // Set J
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- Tensor<Real,true,COORD_DIM> b, n;
|
|
|
- b(0) = B[i*COORD_DIM+0][j];
|
|
|
- b(1) = B[i*COORD_DIM+1][j];
|
|
|
- b(2) = B[i*COORD_DIM+2][j];
|
|
|
-
|
|
|
- n(0) = normal[i*COORD_DIM+0][j];
|
|
|
- n(1) = normal[i*COORD_DIM+1][j];
|
|
|
- n(2) = normal[i*COORD_DIM+2][j];
|
|
|
-
|
|
|
- J[i*COORD_DIM+0][j] = n(1) * b(2) - n(2) * b(1);
|
|
|
- J[i*COORD_DIM+1][j] = n(2) * b(0) - n(0) * b(2);
|
|
|
- J[i*COORD_DIM+2][j] = n(0) * b(1) - n(1) * b(0);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- Vector<ElemBasis> A;
|
|
|
- S.quadrature_FxU.Eval(A, S.GetElemList(), J, S.Laplace_FxU);
|
|
|
- return compute_poloidal_circulation_(A)/S.NtNp_[0];
|
|
|
- };
|
|
|
- auto compute_A22 = [&S,&compute_B0,&normal,&compute_poloidal_circulation_](const Real alpha) {
|
|
|
- const Long Nelem = S.GetElemList().NElem();
|
|
|
- const Long Nnodes = ElemBasis::Size();
|
|
|
-
|
|
|
- Vector<ElemBasis> B = compute_B0(alpha);
|
|
|
-
|
|
|
- Vector<ElemBasis> J(Nelem * COORD_DIM);
|
|
|
- for (Long i = 0; i < Nelem; i++) { // Set J
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- Tensor<Real,true,COORD_DIM> b, n;
|
|
|
- b(0) = B[i*COORD_DIM+0][j];
|
|
|
- b(1) = B[i*COORD_DIM+1][j];
|
|
|
- b(2) = B[i*COORD_DIM+2][j];
|
|
|
-
|
|
|
- n(0) = normal[i*COORD_DIM+0][j];
|
|
|
- n(1) = normal[i*COORD_DIM+1][j];
|
|
|
- n(2) = normal[i*COORD_DIM+2][j];
|
|
|
-
|
|
|
- J[i*COORD_DIM+0][j] = n(1) * b(2) - n(2) * b(1);
|
|
|
- J[i*COORD_DIM+1][j] = n(2) * b(0) - n(0) * b(2);
|
|
|
- J[i*COORD_DIM+2][j] = n(0) * b(1) - n(1) * b(0);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- Vector<ElemBasis> A;
|
|
|
- S.quadrature_FxU.Eval(A, S.GetElemList(), J, S.Laplace_FxU);
|
|
|
- return compute_poloidal_circulation_(A)/S.NtNp_[0];
|
|
|
- };
|
|
|
- auto compute_A = [&compute_A11,&compute_A12,&compute_A21,&compute_A22] (const Vector<Real>& x) {
|
|
|
- const Vector<Real> sigma(x.Dim()-1,(Iterator<Real>)x.begin(),false);
|
|
|
- const Real& alpha = x[x.Dim()-1];
|
|
|
-
|
|
|
- Vector<Real> Ax;
|
|
|
- Ax.ReInit(x.Dim());
|
|
|
- Vector<Real> Bdotn(x.Dim()-1,Ax.begin(),false);
|
|
|
- Real& flux = Ax[x.Dim()-1];
|
|
|
-
|
|
|
- Vector<Real> Adotn_0, Adotn_1;
|
|
|
- compute_A11(Adotn_0, sigma);
|
|
|
- compute_A12(Adotn_1, alpha);
|
|
|
- Bdotn = Adotn_0 + Adotn_1;
|
|
|
-
|
|
|
- flux = compute_A21(sigma) + compute_A22(alpha);
|
|
|
- return Ax;
|
|
|
- };
|
|
|
- auto compute_invA = [&S,&comm,&compute_A] (Vector<ElemBasis>& sigma, Real& alpha, Real flux) {
|
|
|
- typename sctl::ParallelSolver<Real>::ParallelOp BIOp = [&compute_A](sctl::Vector<Real>* Ax, const sctl::Vector<Real>& x) {
|
|
|
- (*Ax) = compute_A(x);
|
|
|
- };
|
|
|
- const Long Nelem = S.GetElemList().NElem();
|
|
|
- const Long Nnodes = ElemBasis::Size();
|
|
|
-
|
|
|
- Vector<Real> rhs_(Nelem * Nnodes + 1);
|
|
|
- rhs_ = 0;
|
|
|
- rhs_[Nelem * Nnodes] = flux;
|
|
|
-
|
|
|
- Vector<Real> x_(Nelem * Nnodes + 1);
|
|
|
- x_ = 0;
|
|
|
- ParallelSolver<Real> linear_solver(comm, true);
|
|
|
- linear_solver(&x_, BIOp, rhs_, 1e-8, 50);
|
|
|
-
|
|
|
- sigma.ReInit(Nelem);
|
|
|
- for (Long i = 0; i < Nelem; i++) {
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- sigma[i][j] = x_[i*Nnodes+j];
|
|
|
- }
|
|
|
- }
|
|
|
- alpha = x_[Nelem * Nnodes];
|
|
|
- };
|
|
|
- auto compute_invA_ = [&S,&comm,&compute_A] (Vector<Real>& b) {
|
|
|
- typename sctl::ParallelSolver<Real>::ParallelOp BIOp = [&compute_A](sctl::Vector<Real>* Ax, const sctl::Vector<Real>& x) {
|
|
|
- (*Ax) = compute_A(x);
|
|
|
- };
|
|
|
- const Long Nelem = S.GetElemList().NElem();
|
|
|
- const Long Nnodes = ElemBasis::Size();
|
|
|
-
|
|
|
- Vector<Real> x(b.Dim());
|
|
|
- x = 0;
|
|
|
- ParallelSolver<Real> linear_solver(comm, true);
|
|
|
- linear_solver(&x, BIOp, b, 1e-8, 50);
|
|
|
- return x;
|
|
|
- };
|
|
|
-
|
|
|
- /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
- /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
- Real flux = 1.0, alpha;
|
|
|
- Vector<ElemBasis> sigma(S.GetElemList().NElem());
|
|
|
- compute_invA(sigma, alpha, flux);
|
|
|
- Vector<ElemBasis> B = compute_half_n_plus_dG(sigma) + compute_B0(alpha);
|
|
|
- Real g = compute_inner_prod(B, B);
|
|
|
- std::cout<<"g = "<<g<<'\n';
|
|
|
-
|
|
|
- { // Write VTU
|
|
|
- VTUData vtu;
|
|
|
- vtu.AddElems(S.GetElemList(), sigma, ORDER);
|
|
|
- vtu.WriteVTK("sigma", comm);
|
|
|
- }
|
|
|
- { // Write VTU
|
|
|
- VTUData vtu;
|
|
|
- vtu.AddElems(S.GetElemList(), B, ORDER);
|
|
|
- vtu.WriteVTK("B", comm);
|
|
|
- }
|
|
|
- { // Write VTU
|
|
|
- VTUData vtu;
|
|
|
- vtu.AddElems(S.GetElemList(), area_elem, ORDER);
|
|
|
- vtu.WriteVTK("area_elem", comm);
|
|
|
- }
|
|
|
-
|
|
|
- /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
- /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
-
|
|
|
- auto compute_B = [&sigma,&alpha,&S,&area_elem,&normal,&compute_norm_area_elem,&compute_invA,&compute_half_n_plus_dG,&compute_B0,&compute_inner_prod,&comm] (const Vector<ElemBasis>& nu, Real eps) {
|
|
|
- const Long Nelem = S.GetElemList().NElem();
|
|
|
- const Long Nnodes = ElemBasis::Size();
|
|
|
-
|
|
|
- Vector<ElemBasis> X_orig(Nelem*COORD_DIM);
|
|
|
- for (Long i = 0; i < Nelem; i++) {
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- X_orig[i*COORD_DIM+0][j] = S.Elem(i,0)[j];
|
|
|
- X_orig[i*COORD_DIM+1][j] = S.Elem(i,1)[j];
|
|
|
- X_orig[i*COORD_DIM+2][j] = S.Elem(i,2)[j];
|
|
|
- S.Elem(i,0)[j] += eps*nu[i][j] * normal[i*COORD_DIM+0][j];
|
|
|
- S.Elem(i,1)[j] += eps*nu[i][j] * normal[i*COORD_DIM+1][j];
|
|
|
- S.Elem(i,2)[j] += eps*nu[i][j] * normal[i*COORD_DIM+2][j];
|
|
|
- }
|
|
|
- }
|
|
|
- compute_norm_area_elem(normal, area_elem);
|
|
|
- S.quadrature_FxdU.template Setup<ElemBasis, ElemBasis>(S.GetElemList(), S.Laplace_FxdU, order_singular, order_direct, -1.0, comm);
|
|
|
-
|
|
|
- Real flux = 1.0, alpha;
|
|
|
- Vector<ElemBasis> sigma;
|
|
|
- compute_invA(sigma, alpha, flux);
|
|
|
- Vector<ElemBasis> B = compute_half_n_plus_dG(sigma) + compute_B0(alpha);
|
|
|
-
|
|
|
- for (Long i = 0; i < Nelem; i++) {
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- S.Elem(i,0)[j] = X_orig[i*COORD_DIM+0][j];
|
|
|
- S.Elem(i,1)[j] = X_orig[i*COORD_DIM+1][j];
|
|
|
- S.Elem(i,2)[j] = X_orig[i*COORD_DIM+2][j];
|
|
|
- }
|
|
|
- }
|
|
|
- compute_norm_area_elem(normal, area_elem);
|
|
|
- S.quadrature_FxdU.template Setup<ElemBasis, ElemBasis>(S.GetElemList(), S.Laplace_FxdU, order_singular, order_direct, -1.0, comm);
|
|
|
-
|
|
|
- return B;
|
|
|
- };
|
|
|
-
|
|
|
- {
|
|
|
- const Long Nelem = S.GetElemList().NElem();
|
|
|
- const Long Nnodes = ElemBasis::Size();
|
|
|
- Real eps = 1e-5;
|
|
|
-
|
|
|
- Vector<ElemBasis> nu(Nelem);
|
|
|
- nu = 1; //area_elem;
|
|
|
-
|
|
|
- Vector<ElemBasis> mytest;
|
|
|
- { // compute nu_n_dot_gradB_dot_n
|
|
|
- auto compute_B_perturb_trg = [&S,&comm,&area_elem,&normal,&compute_norm_area_elem,&compute_dot_prod,&sigma,&alpha,&compute_B0](const Vector<ElemBasis>& nu, Real eps) {
|
|
|
- const Long Nelem = S.GetElemList().NElem();
|
|
|
- const Long Nnodes = ElemBasis::Size();
|
|
|
-
|
|
|
- Vector<ElemBasis> X_orig(Nelem*COORD_DIM);
|
|
|
- for (Long i = 0; i < Nelem; i++) {
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- X_orig[i*COORD_DIM+0][j] = S.Elem(i,0)[j];
|
|
|
- X_orig[i*COORD_DIM+1][j] = S.Elem(i,1)[j];
|
|
|
- X_orig[i*COORD_DIM+2][j] = S.Elem(i,2)[j];
|
|
|
- S.Elem(i,0)[j] = S.Elem(i,0)[j] - 1e-4*normal[i*COORD_DIM+0][j] + eps*nu[i][j] * normal[i*COORD_DIM+0][j];
|
|
|
- S.Elem(i,1)[j] = S.Elem(i,1)[j] - 1e-4*normal[i*COORD_DIM+1][j] + eps*nu[i][j] * normal[i*COORD_DIM+1][j];
|
|
|
- S.Elem(i,2)[j] = S.Elem(i,2)[j] - 1e-4*normal[i*COORD_DIM+2][j] + eps*nu[i][j] * normal[i*COORD_DIM+2][j];
|
|
|
- }
|
|
|
- }
|
|
|
- compute_norm_area_elem(normal, area_elem);
|
|
|
- Vector<ElemBasis> my_normal = normal;
|
|
|
- Vector<ElemBasis> B0 = compute_B0(alpha);
|
|
|
- for (Long i = 0; i < Nelem; i++) {
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- S.Elem(i,0)[j] = X_orig[i*COORD_DIM+0][j];
|
|
|
- S.Elem(i,1)[j] = X_orig[i*COORD_DIM+1][j];
|
|
|
- S.Elem(i,2)[j] = X_orig[i*COORD_DIM+2][j];
|
|
|
- }
|
|
|
- }
|
|
|
- compute_norm_area_elem(normal, area_elem);
|
|
|
-
|
|
|
- Vector<Real> Xt(Nelem*Nnodes*COORD_DIM);
|
|
|
- for (Long i = 0; i < Nelem; i++) {
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- for (Long k = 0; k < COORD_DIM; k++) {
|
|
|
- Xt[(i*Nnodes+j)*COORD_DIM+k] = S.Elem(i,k)[j] - 1e-4*normal[i*COORD_DIM+k][j] + eps*nu[i][j] * normal[i*COORD_DIM+k][j];
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- Vector<ElemBasis> B1;
|
|
|
- Quadrature<Real> quadrature_FxdU;
|
|
|
- quadrature_FxdU.template Setup<ElemBasis>(S.GetElemList(), Xt, S.Laplace_FxdU, order_singular, order_direct, -1, comm);
|
|
|
- quadrature_FxdU.Eval(B1, S.GetElemList(), sigma, S.Laplace_FxdU);
|
|
|
-
|
|
|
- return compute_dot_prod(B0+B1,my_normal);
|
|
|
- };
|
|
|
- mytest = (compute_B_perturb_trg(nu,eps) - compute_B_perturb_trg(nu,-eps)) * (1/(2*eps));
|
|
|
- }
|
|
|
- { // Write VTU
|
|
|
- VTUData vtu;
|
|
|
- vtu.AddElems(S.GetElemList(), mytest, ORDER);
|
|
|
- vtu.WriteVTK("mytest", comm);
|
|
|
- }
|
|
|
-
|
|
|
- Vector<ElemBasis> nu_divB(Nelem);
|
|
|
- { // compute nu_divB
|
|
|
- nu_divB = compute_div(B);
|
|
|
- for (Long i = 0; i < Nelem; i++) {
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- nu_divB[i][j] *= nu[i][j];
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- { // Write VTU
|
|
|
- VTUData vtu;
|
|
|
- vtu.AddElems(S.GetElemList(), nu_divB, ORDER);
|
|
|
- vtu.WriteVTK("nu_divB", comm);
|
|
|
- }
|
|
|
-
|
|
|
- Vector<ElemBasis> B_dot_grad_nu;
|
|
|
- B_dot_grad_nu = compute_dot_prod(B, compute_grad(nu));
|
|
|
- { // Write VTU
|
|
|
- VTUData vtu;
|
|
|
- vtu.AddElems(S.GetElemList(), B_dot_grad_nu, ORDER);
|
|
|
- vtu.WriteVTK("B_dot_grad_nu", comm);
|
|
|
- }
|
|
|
-
|
|
|
- Vector<ElemBasis> dBdnu_dot_n;
|
|
|
- { // compute dBdnu_dot_n
|
|
|
- auto B0 = compute_B(nu,-eps);
|
|
|
- auto B1 = compute_B(nu,eps);
|
|
|
- dBdnu_dot_n = compute_dot_prod((B1-B0)*(1.0/(2.0*eps)), normal);
|
|
|
- }
|
|
|
- { // Write VTU
|
|
|
- VTUData vtu;
|
|
|
- vtu.AddElems(S.GetElemList(), dBdnu_dot_n, ORDER);
|
|
|
- vtu.WriteVTK("dBdnu_dot_n", comm);
|
|
|
- }
|
|
|
-
|
|
|
- { // Write VTU
|
|
|
- VTUData vtu;
|
|
|
- vtu.AddElems(S.GetElemList(), dBdnu_dot_n-B_dot_grad_nu, ORDER);
|
|
|
- vtu.WriteVTK("err0", comm);
|
|
|
- }
|
|
|
- { // Write VTU
|
|
|
- VTUData vtu;
|
|
|
- vtu.AddElems(S.GetElemList(), mytest+B_dot_grad_nu+nu_divB, ORDER);
|
|
|
- vtu.WriteVTK("err1", comm);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
- /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
- }
|
|
|
-
|
|
|
private:
|
|
|
void InitSurf(Long l) {
|
|
|
const auto& nodes = ElemBasis::Nodes();
|