|  | @@ -2518,364 +2518,6 @@ template <class Real, Integer ORDER=10> class Stellarator {
 | 
	
		
			
				|  |  |        SetupQuadrature(S.quadrature_dUxD , S, S.Laplace_dUxD  , order_singular, order_direct, -1.0, comm,  0.01 * pow<-2,Real>(ORDER));
 | 
	
		
			
				|  |  |        SetupQuadrature(S.quadrature_Fxd2U, S, S.Laplace_Fxd2U , order_singular, order_direct, -1.0, comm, -0.01 * pow<-2,Real>(ORDER));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -      {
 | 
	
		
			
				|  |  | -      auto compute_A = [&S,&Jt,&Jp] (const Vector<Real>& x) {
 | 
	
		
			
				|  |  | -        Vector<ElemBasis> normal, area_elem;
 | 
	
		
			
				|  |  | -        compute_norm_area_elem(S, normal, area_elem);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        auto compute_B0 = [&S, &Jp](const Real alpha) {
 | 
	
		
			
				|  |  | -          Vector<ElemBasis> B0;
 | 
	
		
			
				|  |  | -          S.quadrature_BS.Eval(B0, S.GetElemList(), Jp, S.BiotSavart);
 | 
	
		
			
				|  |  | -          return B0*alpha;
 | 
	
		
			
				|  |  | -        };
 | 
	
		
			
				|  |  | -        auto compute_half_n_plus_dG = [&S, &normal](const Vector<ElemBasis>& sigma) { // B = n sigma/2 + dG[sigma]
 | 
	
		
			
				|  |  | -          const Long Nelem = S.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](Vector<Real>& B_dot_n, const Vector<Real>& sigma) {
 | 
	
		
			
				|  |  | -          const Long Nelem = S.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_B0](Vector<Real>& B_dot_n, const Real alpha) {
 | 
	
		
			
				|  |  | -          const Long Nelem = S.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](const Vector<Real>& sigma) {
 | 
	
		
			
				|  |  | -          const Long Nelem = S.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];
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -          }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -          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);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -          Real pol_circ = 0;
 | 
	
		
			
				|  |  | -          { // compute pol_circ
 | 
	
		
			
				|  |  | -            Vector<ElemBasis> dX;
 | 
	
		
			
				|  |  | -            ElemBasis::Grad(dX, S.GetElemList().ElemVector());
 | 
	
		
			
				|  |  | -            const auto& quad_wts = ElemBasis::QuadWts();
 | 
	
		
			
				|  |  | -            for (Long i = 0; i < Nelem; i++) {
 | 
	
		
			
				|  |  | -              for (Long j = 0; j < Nnodes; j++) {
 | 
	
		
			
				|  |  | -                pol_circ += A[i*COORD_DIM+0][j] * dX[i*COORD_DIM*2+1][j] * quad_wts[j] / S.NtNp_[0];
 | 
	
		
			
				|  |  | -                pol_circ += A[i*COORD_DIM+1][j] * dX[i*COORD_DIM*2+3][j] * quad_wts[j] / S.NtNp_[0];
 | 
	
		
			
				|  |  | -                pol_circ += A[i*COORD_DIM+2][j] * dX[i*COORD_DIM*2+5][j] * quad_wts[j] / S.NtNp_[0];
 | 
	
		
			
				|  |  | -              }
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -          }
 | 
	
		
			
				|  |  | -          return pol_circ;
 | 
	
		
			
				|  |  | -        };
 | 
	
		
			
				|  |  | -        auto compute_A22 = [&S,&compute_B0,&normal](const Real alpha) {
 | 
	
		
			
				|  |  | -          const Long Nelem = S.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);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -          Real pol_circ = 0;
 | 
	
		
			
				|  |  | -          { // compute pol_circ
 | 
	
		
			
				|  |  | -            Vector<ElemBasis> dX;
 | 
	
		
			
				|  |  | -            ElemBasis::Grad(dX, S.GetElemList().ElemVector());
 | 
	
		
			
				|  |  | -            const auto& quad_wts = ElemBasis::QuadWts();
 | 
	
		
			
				|  |  | -            for (Long i = 0; i < Nelem; i++) {
 | 
	
		
			
				|  |  | -              for (Long j = 0; j < Nnodes; j++) {
 | 
	
		
			
				|  |  | -                pol_circ += A[i*COORD_DIM+0][j] * dX[i*COORD_DIM*2+1][j] * quad_wts[j] / S.NtNp_[0];
 | 
	
		
			
				|  |  | -                pol_circ += A[i*COORD_DIM+1][j] * dX[i*COORD_DIM*2+3][j] * quad_wts[j] / S.NtNp_[0];
 | 
	
		
			
				|  |  | -                pol_circ += A[i*COORD_DIM+2][j] * dX[i*COORD_DIM*2+5][j] * quad_wts[j] / S.NtNp_[0];
 | 
	
		
			
				|  |  | -              }
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -          }
 | 
	
		
			
				|  |  | -          return pol_circ;
 | 
	
		
			
				|  |  | -        };
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        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.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_Aadj = [&S,&Jt,&Jp] (const Vector<Real>& x) {
 | 
	
		
			
				|  |  | -        Vector<ElemBasis> normal, area_elem;
 | 
	
		
			
				|  |  | -        compute_norm_area_elem(S, normal, area_elem);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        auto compute_B0 = [&S, &Jp](const Real alpha) {
 | 
	
		
			
				|  |  | -          Vector<ElemBasis> B0;
 | 
	
		
			
				|  |  | -          S.quadrature_BS.Eval(B0, S.GetElemList(), Jp, S.BiotSavart);
 | 
	
		
			
				|  |  | -          return B0*alpha;
 | 
	
		
			
				|  |  | -        };
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        auto compute_A12 = [&S,&normal,&compute_B0](Vector<Real>& B_dot_n, const Real alpha) {
 | 
	
		
			
				|  |  | -          const Long Nelem = S.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_A22 = [&S,&compute_B0,&normal](const Real alpha) {
 | 
	
		
			
				|  |  | -          const Long Nelem = S.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);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -          Real pol_circ = 0;
 | 
	
		
			
				|  |  | -          { // compute pol_circ
 | 
	
		
			
				|  |  | -            Vector<ElemBasis> dX;
 | 
	
		
			
				|  |  | -            ElemBasis::Grad(dX, S.GetElemList().ElemVector());
 | 
	
		
			
				|  |  | -            const auto& quad_wts = ElemBasis::QuadWts();
 | 
	
		
			
				|  |  | -            for (Long i = 0; i < Nelem; i++) {
 | 
	
		
			
				|  |  | -              for (Long j = 0; j < Nnodes; j++) {
 | 
	
		
			
				|  |  | -                pol_circ += A[i*COORD_DIM+0][j] * dX[i*COORD_DIM*2+1][j] * quad_wts[j] / S.NtNp_[0];
 | 
	
		
			
				|  |  | -                pol_circ += A[i*COORD_DIM+1][j] * dX[i*COORD_DIM*2+3][j] * quad_wts[j] / S.NtNp_[0];
 | 
	
		
			
				|  |  | -                pol_circ += A[i*COORD_DIM+2][j] * dX[i*COORD_DIM*2+5][j] * quad_wts[j] / S.NtNp_[0];
 | 
	
		
			
				|  |  | -              }
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -          }
 | 
	
		
			
				|  |  | -          return pol_circ;
 | 
	
		
			
				|  |  | -        };
 | 
	
		
			
				|  |  | -        auto compute_A11adj = [&S,&normal](Vector<Real>& U, const Vector<Real>& sigma) { // A11adj  = I/2 + D
 | 
	
		
			
				|  |  | -          const Long Nelem = S.NElem();
 | 
	
		
			
				|  |  | -          const Long Nnodes = ElemBasis::Size();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -          Vector<ElemBasis> sigma_n(Nelem*COORD_DIM);
 | 
	
		
			
				|  |  | -          for (Long i = 0; i < Nelem; i++) {
 | 
	
		
			
				|  |  | -            for (Long j = 0; j < Nnodes; j++) {
 | 
	
		
			
				|  |  | -              sigma_n[i*COORD_DIM+0][j] = sigma[i*Nnodes+j] * normal[i*COORD_DIM+0][j];
 | 
	
		
			
				|  |  | -              sigma_n[i*COORD_DIM+1][j] = sigma[i*Nnodes+j] * normal[i*COORD_DIM+1][j];
 | 
	
		
			
				|  |  | -              sigma_n[i*COORD_DIM+2][j] = sigma[i*Nnodes+j] * normal[i*COORD_DIM+2][j];
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -          }
 | 
	
		
			
				|  |  | -          S.quadrature_dUxF.Eval(U, S.GetElemList(), sigma_n*(-1), S.Laplace_dUxF);
 | 
	
		
			
				|  |  | -          U = sigma*(-0.5) + U;
 | 
	
		
			
				|  |  | -        };
 | 
	
		
			
				|  |  | -        auto compute_A12adj = [&S,&compute_A12,&area_elem](const Vector<Real>& sigma_) {
 | 
	
		
			
				|  |  | -          const Long Nelem = S.NElem();
 | 
	
		
			
				|  |  | -          const Long Nnodes = ElemBasis::Size();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -          Vector<Real> A12_sigma_;
 | 
	
		
			
				|  |  | -          compute_A12(A12_sigma_, 1);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -          Vector<ElemBasis> A12_sigma(Nelem), sigma(Nelem);
 | 
	
		
			
				|  |  | -          for (Long i = 0; i < Nelem; i++) {
 | 
	
		
			
				|  |  | -            for (Long j = 0; j < Nnodes; j++) {
 | 
	
		
			
				|  |  | -              sigma[i][j] = sigma_[i*Nnodes+j];
 | 
	
		
			
				|  |  | -              A12_sigma[i][j] = A12_sigma_[i*Nnodes+j];
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -          }
 | 
	
		
			
				|  |  | -          return compute_inner_prod(area_elem, A12_sigma, sigma);
 | 
	
		
			
				|  |  | -        };
 | 
	
		
			
				|  |  | -        auto compute_A21adj = [&S,&area_elem,&normal](Vector<Real>& A21adj_flux, Real flux) {
 | 
	
		
			
				|  |  | -          const Long Nelem = S.NElem();
 | 
	
		
			
				|  |  | -          const Long Nnodes = ElemBasis::Size();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -          Vector<ElemBasis> density(Nelem * COORD_DIM);
 | 
	
		
			
				|  |  | -          { // Set density
 | 
	
		
			
				|  |  | -            Vector<ElemBasis> dX;
 | 
	
		
			
				|  |  | -            ElemBasis::Grad(dX, S.GetElemList().ElemVector());
 | 
	
		
			
				|  |  | -            for (Long i = 0; i < Nelem; i++) {
 | 
	
		
			
				|  |  | -              for (Long j = 0; j < Nnodes; j++) {
 | 
	
		
			
				|  |  | -                Real s = 1 / (area_elem[i][j] * S.NtNp_[0]);
 | 
	
		
			
				|  |  | -                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;
 | 
	
		
			
				|  |  | -              }
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -          }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -          Vector<ElemBasis> Gdensity;
 | 
	
		
			
				|  |  | -          S.quadrature_FxU.Eval(Gdensity, S.GetElemList(), density, S.Laplace_FxU);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -          Vector<ElemBasis> nxGdensity(Nelem * COORD_DIM);
 | 
	
		
			
				|  |  | -          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);
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -          }
 | 
	
		
			
				|  |  | -          S.quadrature_dUxF.Eval(A21adj_flux, S.GetElemList(), nxGdensity, S.Laplace_dUxF);
 | 
	
		
			
				|  |  | -          A21adj_flux *= flux;
 | 
	
		
			
				|  |  | -        };
 | 
	
		
			
				|  |  | -        auto compute_A22adj = [&compute_A22] (const Real alpha) {
 | 
	
		
			
				|  |  | -          return compute_A22(alpha);
 | 
	
		
			
				|  |  | -        };
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        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_A11adj(Adotn_0, sigma);
 | 
	
		
			
				|  |  | -        compute_A21adj(Adotn_1, alpha);
 | 
	
		
			
				|  |  | -        Bdotn = Adotn_0 + Adotn_1;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        flux = compute_A12adj(sigma) + compute_A22adj(alpha);
 | 
	
		
			
				|  |  | -        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, 50);
 | 
	
		
			
				|  |  | -        return x;
 | 
	
		
			
				|  |  | -      };
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |        Vector<ElemBasis> Bt0, Bp0;
 | 
	
		
			
				|  |  |        Vector<ElemBasis> Jt, Jp;
 | 
	
		
			
				|  |  |        { // Set Bt0, Bp0
 |