|
@@ -2716,6 +2716,7 @@ template <class Real, Integer ORDER=10> class Stellarator {
|
|
|
Ax2 = (S.Nsurf() >= 2 ? compute_inner_prod(area_elem, compute_dot_prod(Bp0, normal), x0) : 0);
|
|
|
}
|
|
|
|
|
|
+ // TODO: precompute A21adj, A22adj
|
|
|
auto compute_A21adj = [&S,&normal,&area_elem] (bool toroidal_flux) {
|
|
|
const Long Nelem = S.NElem();
|
|
|
const Long Nnodes = ElemBasis::Size();
|
|
@@ -2776,7 +2777,6 @@ template <class Real, Integer ORDER=10> class Stellarator {
|
|
|
};
|
|
|
if (S.Nsurf() >= 1) Ax0 += compute_A21adj( true) * x1;
|
|
|
if (S.Nsurf() >= 2) Ax0 += compute_A21adj(false) * x2;
|
|
|
-
|
|
|
if (S.Nsurf() == 1) { // Add flux part of Ax1, Ax2
|
|
|
Real flux_tor, flux_pol;
|
|
|
compute_flux(flux_tor, flux_pol, Bt0, normal);
|
|
@@ -2816,6 +2816,65 @@ template <class Real, Integer ORDER=10> class Stellarator {
|
|
|
return x;
|
|
|
};
|
|
|
|
|
|
+ if (0) { // Check u_t A v == v_t Aadj u
|
|
|
+ auto pack = [&S](Vector<Real>& x, const Vector<ElemBasis>& x0, Real x1, Real x2) {
|
|
|
+ const Long Nelem = S.NElem();
|
|
|
+ const Long Nnodes = ElemBasis::Size();
|
|
|
+ x.ReInit(Nelem*Nnodes+S.Nsurf());
|
|
|
+ for (Long i = 0; i < Nelem; i++) {
|
|
|
+ for (Long j = 0; j < Nnodes; j++) {
|
|
|
+ x[i*Nnodes+j] = x0[i][j];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (S.Nsurf() >= 1) x[Nelem*Nnodes+0] = x1;
|
|
|
+ if (S.Nsurf() >= 2) x[Nelem*Nnodes+1] = x2;
|
|
|
+ };
|
|
|
+ auto unpack = [&S](Vector<ElemBasis>& x0, Real& x1, Real& x2, const Vector<Real>& x) {
|
|
|
+ const Long Nelem = S.NElem();
|
|
|
+ const Long Nnodes = ElemBasis::Size();
|
|
|
+ x0.ReInit(Nelem);
|
|
|
+ for (Long i = 0; i < Nelem; i++) {
|
|
|
+ for (Long j = 0; j < Nnodes; j++) {
|
|
|
+ x0[i][j] = x[i*Nnodes+j];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (S.Nsurf() >= 1) x1 = x[Nelem*Nnodes+0];
|
|
|
+ if (S.Nsurf() >= 2) x2 = x[Nelem*Nnodes+1];
|
|
|
+ };
|
|
|
+ const Long Nelem = S.NElem();
|
|
|
+ const Long Nnodes = ElemBasis::Size();
|
|
|
+
|
|
|
+ Vector<ElemBasis> normal, area_elem;
|
|
|
+ compute_norm_area_elem(S, normal, area_elem);
|
|
|
+
|
|
|
+ Vector<Real> u, v;
|
|
|
+ Vector<ElemBasis> u0 = area_elem*0; Real u1 = 3.141, u2 = 0.4142;
|
|
|
+ Vector<ElemBasis> v0 = area_elem*0; Real v1 = 1.645, v2 = 3.6055;
|
|
|
+ { // Set u0, v0
|
|
|
+ auto X = S.GetElemList().ElemVector();
|
|
|
+ for (Long i = 0; i < Nelem; i++) {
|
|
|
+ for (Long j = 0; j < Nnodes; j++) {
|
|
|
+ u0[i][j] = X[i*COORD_DIM+0][j] + X[i*COORD_DIM+1][j] + X[i*COORD_DIM+2][j];
|
|
|
+ v0[i][j] = X[i*COORD_DIM+0][j] + X[i*COORD_DIM+1][j] + X[i*COORD_DIM+2][j];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ pack(u,u0,u1,u2);
|
|
|
+ pack(v,v0,v1,v2);
|
|
|
+
|
|
|
+ Vector<Real> Av = compute_A(v);
|
|
|
+ Vector<Real> uA = compute_Aadj(u);
|
|
|
+
|
|
|
+ Vector<ElemBasis> Av0; Real Av1, Av2;
|
|
|
+ Vector<ElemBasis> uA0; Real uA1, uA2;
|
|
|
+ unpack(Av0, Av1, Av2, Av);
|
|
|
+ unpack(uA0, uA1, uA2, uA);
|
|
|
+
|
|
|
+ std::cout << compute_inner_prod(area_elem, u0, Av0) + u1*Av1 + (S.Nsurf()>=2?u2*Av2:0) << '\n';
|
|
|
+ std::cout << compute_inner_prod(area_elem, uA0, v0) + uA1*v1 + (S.Nsurf()>=2?uA2*v2:0) << '\n';
|
|
|
+ exit(0);
|
|
|
+ }
|
|
|
+
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
@@ -3618,199 +3677,6 @@ template <class Real, Integer ORDER=10> class Stellarator {
|
|
|
alpha = (S.Nsurf() >= 1 ? x_[Nelem * Nnodes + 0] : 0);
|
|
|
beta = (S.Nsurf() >= 2 ? x_[Nelem * Nnodes + 1] : 0);
|
|
|
};
|
|
|
- auto compute_Aadj = [&S,&Bt0,&Bp0,&compute_flux] (const Vector<Real>& x) {
|
|
|
- const Long Nelem = S.NElem();
|
|
|
- const Long Nnodes = ElemBasis::Size();
|
|
|
- SCTL_ASSERT(x.Dim() == Nelem*Nnodes+S.Nsurf());
|
|
|
-
|
|
|
- Vector<ElemBasis> normal, area_elem;
|
|
|
- compute_norm_area_elem(S, normal, area_elem);
|
|
|
-
|
|
|
- Vector<ElemBasis> x0(Nelem);
|
|
|
- for (Long i = 0; i < Nelem; i++) {
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- x0[i][j] = x[i*Nnodes+j];
|
|
|
- }
|
|
|
- }
|
|
|
- Real x1 = (S.Nsurf() >= 1 ? x[Nelem*Nnodes + 0] : 0);
|
|
|
- Real x2 = (S.Nsurf() >= 2 ? x[Nelem*Nnodes + 1] : 0);
|
|
|
-
|
|
|
- Vector<ElemBasis> Ax0;
|
|
|
- Real Ax1, Ax2;
|
|
|
- { // Set Ax0, Ax1, Ax2
|
|
|
- Vector<ElemBasis> x0_n(Nelem*COORD_DIM);
|
|
|
- for (Long i = 0; i < Nelem; i++) {
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- x0_n[i*COORD_DIM+0][j] = x0[i][j] * normal[i*COORD_DIM+0][j];
|
|
|
- x0_n[i*COORD_DIM+1][j] = x0[i][j] * normal[i*COORD_DIM+1][j];
|
|
|
- x0_n[i*COORD_DIM+2][j] = x0[i][j] * normal[i*COORD_DIM+2][j];
|
|
|
- }
|
|
|
- }
|
|
|
- EvalQuadrature(Ax0, S.quadrature_dUxF, S, x0_n, S.Laplace_dUxF);
|
|
|
- Ax0 = x0*(-0.5) - Ax0;
|
|
|
-
|
|
|
- Ax1 = (S.Nsurf() >= 1 ? compute_inner_prod(area_elem, compute_dot_prod(Bt0, normal), x0) : 0);
|
|
|
- Ax2 = (S.Nsurf() >= 2 ? compute_inner_prod(area_elem, compute_dot_prod(Bp0, normal), x0) : 0);
|
|
|
- }
|
|
|
-
|
|
|
- auto compute_A21adj = [&S,&normal,&area_elem] (bool toroidal_flux) {
|
|
|
- const Long Nelem = S.NElem();
|
|
|
- const Long Nnodes = ElemBasis::Size();
|
|
|
- Vector<ElemBasis> density(Nelem * COORD_DIM);
|
|
|
- { // Set density
|
|
|
- Real scal[2];
|
|
|
- if (S.Nsurf() == 1) {
|
|
|
- SCTL_ASSERT(toroidal_flux == true);
|
|
|
- scal[0] = 1.0 / S.NTor(0);
|
|
|
- scal[1] = 0;
|
|
|
- } else if (S.Nsurf() == 2) {
|
|
|
- if (toroidal_flux == true) {
|
|
|
- scal[0] = -1.0 / S.NTor(0);
|
|
|
- scal[1] = 1.0 / S.NTor(1);
|
|
|
- } else {
|
|
|
- scal[0] = 1.0 / S.NPol(0);
|
|
|
- scal[1] = -1.0 / S.NPol(1);
|
|
|
- }
|
|
|
- } else {
|
|
|
- SCTL_ASSERT(false);
|
|
|
- }
|
|
|
-
|
|
|
- Vector<ElemBasis> dX;
|
|
|
- ElemBasis::Grad(dX, S.GetElemList().ElemVector());
|
|
|
- for (Long k = 0; k < S.Nsurf(); k++) {
|
|
|
- for (Long i_ = 0; i_ < S.NTor(k)*S.NPol(k); i_++) {
|
|
|
- Long i = S.ElemDsp(k) + i_;
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- Real s = scal[k] / area_elem[i][j];
|
|
|
- density[i*COORD_DIM+0][j] = dX[i*COORD_DIM*2+0+(toroidal_flux?1:0)][j] * s;
|
|
|
- density[i*COORD_DIM+1][j] = dX[i*COORD_DIM*2+2+(toroidal_flux?1:0)][j] * s;
|
|
|
- density[i*COORD_DIM+2][j] = dX[i*COORD_DIM*2+4+(toroidal_flux?1:0)][j] * s;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- Vector<ElemBasis> Gdensity, nxGdensity(Nelem * COORD_DIM), A21adj;
|
|
|
- EvalQuadrature(Gdensity, S.quadrature_FxU, S, density, S.Laplace_FxU);
|
|
|
- for (Long i = 0; i < Nelem; i++) { // Set nxGdensity
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- Tensor<Real,true,COORD_DIM> Gdensity_, n;
|
|
|
- Gdensity_(0) = Gdensity[i*COORD_DIM+0][j];
|
|
|
- Gdensity_(1) = Gdensity[i*COORD_DIM+1][j];
|
|
|
- Gdensity_(2) = Gdensity[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];
|
|
|
-
|
|
|
- nxGdensity[i*COORD_DIM+0][j] = n(1) * Gdensity_(2) - n(2) * Gdensity_(1);
|
|
|
- nxGdensity[i*COORD_DIM+1][j] = n(2) * Gdensity_(0) - n(0) * Gdensity_(2);
|
|
|
- nxGdensity[i*COORD_DIM+2][j] = n(0) * Gdensity_(1) - n(1) * Gdensity_(0);
|
|
|
- }
|
|
|
- }
|
|
|
- EvalQuadrature(A21adj, S.quadrature_dUxF, S, nxGdensity, S.Laplace_dUxF);
|
|
|
- return A21adj;
|
|
|
- };
|
|
|
- if (S.Nsurf() >= 1) Ax0 += compute_A21adj( true) * x1;
|
|
|
- if (S.Nsurf() >= 2) Ax0 += compute_A21adj(false) * x2;
|
|
|
-
|
|
|
- if (S.Nsurf() == 1) { // Add flux part of Ax1, Ax2
|
|
|
- Real flux_tor, flux_pol;
|
|
|
- compute_flux(flux_tor, flux_pol, Bt0, normal);
|
|
|
- Ax1 += flux_tor * x1;
|
|
|
- Ax2 += 0;
|
|
|
- } else if (S.Nsurf() == 2) {
|
|
|
- Real flux_tor, flux_pol;
|
|
|
- compute_flux(flux_tor, flux_pol, Bt0, normal);
|
|
|
- Ax1 += flux_tor * x1 + flux_pol * x2;
|
|
|
- compute_flux(flux_tor, flux_pol, Bp0, normal);
|
|
|
- Ax2 += flux_tor * x1 + flux_pol * x2;
|
|
|
- } else {
|
|
|
- SCTL_ASSERT(false);
|
|
|
- }
|
|
|
-
|
|
|
- Vector<Real> Ax(Nelem*Nnodes+S.Nsurf());
|
|
|
- for (Long i = 0; i < Nelem; i++) {
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- Ax[i*Nnodes+j] = Ax0[i][j];
|
|
|
- }
|
|
|
- }
|
|
|
- if (S.Nsurf() >= 1) Ax[Nelem*Nnodes + 0] = Ax1;
|
|
|
- if (S.Nsurf() >= 2) Ax[Nelem*Nnodes + 1] = Ax2;
|
|
|
- return Ax;
|
|
|
- };
|
|
|
- auto compute_invAadj = [&S,&comm,&compute_Aadj] (Vector<Real>& b) {
|
|
|
- typename sctl::ParallelSolver<Real>::ParallelOp BIOp = [&compute_Aadj](sctl::Vector<Real>* Ax, const sctl::Vector<Real>& x) {
|
|
|
- (*Ax) = compute_Aadj(x);
|
|
|
- };
|
|
|
- const Long Nelem = S.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, 100);
|
|
|
- return x;
|
|
|
- };
|
|
|
-
|
|
|
- if (0) { // Check u_t A v == v_t Aadj u
|
|
|
- auto pack = [&S](Vector<Real>& x, const Vector<ElemBasis>& x0, Real x1, Real x2) {
|
|
|
- const Long Nelem = S.NElem();
|
|
|
- const Long Nnodes = ElemBasis::Size();
|
|
|
- x.ReInit(Nelem*Nnodes+S.Nsurf());
|
|
|
- for (Long i = 0; i < Nelem; i++) {
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- x[i*Nnodes+j] = x0[i][j];
|
|
|
- }
|
|
|
- }
|
|
|
- if (S.Nsurf() >= 1) x[Nelem*Nnodes+0] = x1;
|
|
|
- if (S.Nsurf() >= 2) x[Nelem*Nnodes+1] = x2;
|
|
|
- };
|
|
|
- auto unpack = [&S](Vector<ElemBasis>& x0, Real& x1, Real& x2, const Vector<Real>& x) {
|
|
|
- const Long Nelem = S.NElem();
|
|
|
- const Long Nnodes = ElemBasis::Size();
|
|
|
- x0.ReInit(Nelem);
|
|
|
- for (Long i = 0; i < Nelem; i++) {
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- x0[i][j] = x[i*Nnodes+j];
|
|
|
- }
|
|
|
- }
|
|
|
- if (S.Nsurf() >= 1) x1 = x[Nelem*Nnodes+0];
|
|
|
- if (S.Nsurf() >= 2) x2 = x[Nelem*Nnodes+1];
|
|
|
- };
|
|
|
- const Long Nelem = S.NElem();
|
|
|
- const Long Nnodes = ElemBasis::Size();
|
|
|
-
|
|
|
- Vector<ElemBasis> normal, area_elem;
|
|
|
- compute_norm_area_elem(S, normal, area_elem);
|
|
|
-
|
|
|
- Vector<Real> u, v;
|
|
|
- Vector<ElemBasis> u0 = area_elem*0; Real u1 = 3.141, u2 = 0.4142;
|
|
|
- Vector<ElemBasis> v0 = area_elem*0; Real v1 = 1.645, v2 = 3.6055;
|
|
|
- { // Set u0, v0
|
|
|
- auto X = S.GetElemList().ElemVector();
|
|
|
- for (Long i = 0; i < Nelem; i++) {
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
- u0[i][j] = X[i*COORD_DIM+0][j] + X[i*COORD_DIM+1][j] + X[i*COORD_DIM+2][j];
|
|
|
- v0[i][j] = X[i*COORD_DIM+0][j] + X[i*COORD_DIM+1][j] + X[i*COORD_DIM+2][j];
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- pack(u,u0,u1,u2);
|
|
|
- pack(v,v0,v1,v2);
|
|
|
-
|
|
|
- Vector<Real> Av = compute_A(v);
|
|
|
- Vector<Real> uA = compute_Aadj(u);
|
|
|
-
|
|
|
- Vector<ElemBasis> Av0; Real Av1, Av2;
|
|
|
- Vector<ElemBasis> uA0; Real uA1, uA2;
|
|
|
- unpack(Av0, Av1, Av2, Av);
|
|
|
- unpack(uA0, uA1, uA2, uA);
|
|
|
-
|
|
|
- std::cout << compute_inner_prod(area_elem, u0, Av0) + u1*Av1 + (S.Nsurf()>=2?u2*Av2:0) << '\n';
|
|
|
- std::cout << compute_inner_prod(area_elem, uA0, v0) + uA1*v1 + (S.Nsurf()>=2?uA2*v2:0) << '\n';
|
|
|
- exit(0);
|
|
|
- }
|
|
|
|
|
|
Vector<ElemBasis> dg_dnu = compute_gradient(S, pressure, flux_tor, flux_pol);
|
|
|
{ // Write VTU
|