|  | @@ -2060,8 +2060,8 @@ template <class Real> class Quadrature {
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  template <class Real, Integer ORDER=10> class Stellarator {
 |  |  template <class Real, Integer ORDER=10> class Stellarator {
 | 
											
												
													
														|  |    private:
 |  |    private:
 | 
											
												
													
														|  | -    static constexpr Integer order_singular = 25;
 |  | 
 | 
											
												
													
														|  | -    static constexpr Integer order_direct = 35;
 |  | 
 | 
											
												
													
														|  | 
 |  | +    static constexpr Integer order_singular = 20;
 | 
											
												
													
														|  | 
 |  | +    static constexpr Integer order_direct = 25;
 | 
											
												
													
														|  |      static constexpr Integer COORD_DIM = 3;
 |  |      static constexpr Integer COORD_DIM = 3;
 | 
											
												
													
														|  |      static constexpr Integer ELEM_DIM = COORD_DIM-1;
 |  |      static constexpr Integer ELEM_DIM = COORD_DIM-1;
 | 
											
												
													
														|  |      using ElemBasis = Basis<Real, ELEM_DIM, ORDER>;
 |  |      using ElemBasis = Basis<Real, ELEM_DIM, ORDER>;
 | 
											
										
											
												
													
														|  | @@ -2231,7 +2231,7 @@ template <class Real, Integer ORDER=10> class Stellarator {
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |      static void compute_harmonic_vector_potentials(Vector<ElemBasis>& Jt, Vector<ElemBasis>& Jp, const Stellarator<Real,ORDER>& S) {
 |  |      static void compute_harmonic_vector_potentials(Vector<ElemBasis>& Jt, Vector<ElemBasis>& Jp, const Stellarator<Real,ORDER>& S) {
 | 
											
												
													
														|  |        Comm comm = Comm::World();
 |  |        Comm comm = Comm::World();
 | 
											
												
													
														|  | -      Real gmres_tol = 1e-8;
 |  | 
 | 
											
												
													
														|  | 
 |  | +      Real gmres_tol = 1e-10;
 | 
											
												
													
														|  |        Long max_iter = 100;
 |  |        Long max_iter = 100;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |        auto cheb2grid = [] (const Vector<ElemBasis>& X, Long Mt, Long Mp, Long Nt, Long Np) {
 |  |        auto cheb2grid = [] (const Vector<ElemBasis>& X, Long Mt, Long Mp, Long Nt, Long Np) {
 | 
											
										
											
												
													
														|  | @@ -2343,7 +2343,7 @@ template <class Real, Integer ORDER=10> class Stellarator {
 | 
											
												
													
														|  |        if (Jp.Dim() != Nelem * COORD_DIM) Jp.ReInit(Nelem * COORD_DIM);
 |  |        if (Jp.Dim() != Nelem * COORD_DIM) Jp.ReInit(Nelem * COORD_DIM);
 | 
											
												
													
														|  |        if (Jt.Dim() != Nelem * COORD_DIM) Jt.ReInit(Nelem * COORD_DIM);
 |  |        if (Jt.Dim() != Nelem * COORD_DIM) Jt.ReInit(Nelem * COORD_DIM);
 | 
											
												
													
														|  |        for (Long k = 0; k < S.Nsurf(); k++) {
 |  |        for (Long k = 0; k < S.Nsurf(); k++) {
 | 
											
												
													
														|  | -        Long Nt = S.NTor(k)*ORDER, Np = S.NPol(k)*ORDER;
 |  | 
 | 
											
												
													
														|  | 
 |  | +        Long Nt = S.NTor(k)*ORDER*2, Np = S.NPol(k)*ORDER*2;
 | 
											
												
													
														|  |          const auto& X_ = S.GetElemList().ElemVector();
 |  |          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);
 |  |          Vector<ElemBasis> X(S.NTor(k)*S.NPol(k)*COORD_DIM, (Iterator<ElemBasis>)X_.begin()+S.ElemDsp(k)*COORD_DIM, false);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
										
											
												
													
														|  | @@ -2584,7 +2584,7 @@ template <class Real, Integer ORDER=10> class Stellarator {
 | 
											
												
													
														|  |        Vector<Real> x_(Nelem * Nnodes + S.Nsurf());
 |  |        Vector<Real> x_(Nelem * Nnodes + S.Nsurf());
 | 
											
												
													
														|  |        x_ = 0;
 |  |        x_ = 0;
 | 
											
												
													
														|  |        ParallelSolver<Real> linear_solver(comm, true);
 |  |        ParallelSolver<Real> linear_solver(comm, true);
 | 
											
												
													
														|  | -      linear_solver(&x_, BIOp, rhs_, 1e-6, 100);
 |  | 
 | 
											
												
													
														|  | 
 |  | +      linear_solver(&x_, BIOp, rhs_, 1e-10, 100);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |        sigma.ReInit(Nelem);
 |  |        sigma.ReInit(Nelem);
 | 
											
												
													
														|  |        for (Long i = 0; i < Nelem; i++) {
 |  |        for (Long i = 0; i < Nelem; i++) {
 | 
											
										
											
												
													
														|  | @@ -2739,7 +2739,7 @@ template <class Real, Integer ORDER=10> class Stellarator {
 | 
											
												
													
														|  |        Vector<Real> x(b.Dim());
 |  |        Vector<Real> x(b.Dim());
 | 
											
												
													
														|  |        x = 0;
 |  |        x = 0;
 | 
											
												
													
														|  |        ParallelSolver<Real> linear_solver(comm, true);
 |  |        ParallelSolver<Real> linear_solver(comm, true);
 | 
											
												
													
														|  | -      linear_solver(&x, BIOp, b, 1e-6, 100);
 |  | 
 | 
											
												
													
														|  | 
 |  | +      linear_solver(&x, BIOp, b, 1e-8, 100);
 | 
											
												
													
														|  |        return x;
 |  |        return x;
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
										
											
												
													
														|  | @@ -3657,7 +3657,7 @@ template <class Real, Integer ORDER=10> class Stellarator {
 | 
											
												
													
														|  |            }
 |  |            }
 | 
											
												
													
														|  |          }
 |  |          }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -        SetupQuadrature(S.quadrature_BS   , S, S.BiotSavart    , order_singular, order_direct, -1.0, comm, -0.01 * pow<-2,Real>(ORDER));
 |  | 
 | 
											
												
													
														|  | 
 |  | +        SetupQuadrature(S.quadrature_BS   , S, S.BiotSavart    , order_singular, order_direct, -1.0, comm);//, -0.01 * pow<-2,Real>(ORDER));
 | 
											
												
													
														|  |          SetupQuadrature(S.quadrature_FxU  , S, S.Laplace_FxU   , order_singular, order_direct, -1.0, comm);
 |  |          SetupQuadrature(S.quadrature_FxU  , S, S.Laplace_FxU   , order_singular, order_direct, -1.0, comm);
 | 
											
												
													
														|  |          SetupQuadrature(S.quadrature_FxdU , S, S.Laplace_FxdU  , order_singular, order_direct, -1.0, comm);
 |  |          SetupQuadrature(S.quadrature_FxdU , S, S.Laplace_FxdU  , order_singular, order_direct, -1.0, comm);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
										
											
												
													
														|  | @@ -3666,6 +3666,38 @@ template <class Real, Integer ORDER=10> class Stellarator {
 | 
											
												
													
														|  |            compute_harmonic_vector_potentials(Jt, Jp, S);
 |  |            compute_harmonic_vector_potentials(Jt, Jp, S);
 | 
											
												
													
														|  |            EvalQuadrature(S.Bt0 , S.quadrature_BS , S, Jp, S.BiotSavart);
 |  |            EvalQuadrature(S.Bt0 , S.quadrature_BS , S, Jp, S.BiotSavart);
 | 
											
												
													
														|  |            EvalQuadrature(S.Bp0 , S.quadrature_BS , S, Jt, S.BiotSavart);
 |  |            EvalQuadrature(S.Bp0 , S.quadrature_BS , S, Jt, S.BiotSavart);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +          Vector<ElemBasis> normal, area_elem;
 | 
											
												
													
														|  | 
 |  | +          compute_norm_area_elem(S, normal, area_elem);
 | 
											
												
													
														|  | 
 |  | +          if (S.Nsurf() == 2) {
 | 
											
												
													
														|  | 
 |  | +            Long Nelem0 = S.NTor(0)*S.NPol(0);
 | 
											
												
													
														|  | 
 |  | +            for (Long i = 0; i < Nelem0*COORD_DIM; i++) {
 | 
											
												
													
														|  | 
 |  | +              for (Long j = 0; j < Nnodes; j++) {
 | 
											
												
													
														|  | 
 |  | +                normal[i][j] *= -1.0;
 | 
											
												
													
														|  | 
 |  | +              }
 | 
											
												
													
														|  | 
 |  | +            }
 | 
											
												
													
														|  | 
 |  | +          }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +          const Long Nelem = S.NElem();
 | 
											
												
													
														|  | 
 |  | +          const Long Nnodes = ElemBasis::Size();
 | 
											
												
													
														|  | 
 |  | +          for (Long j = 0; j < Nelem; j++) {
 | 
											
												
													
														|  | 
 |  | +            for (Long k = 0; k < Nnodes; k++) {
 | 
											
												
													
														|  | 
 |  | +              Real Jxn[COORD_DIM];
 | 
											
												
													
														|  | 
 |  | +              Jxn[0] = Jp[j*COORD_DIM+1][k] * normal[j*COORD_DIM+2][k] - Jp[j*COORD_DIM+2][k] * normal[j*COORD_DIM+1][k];
 | 
											
												
													
														|  | 
 |  | +              Jxn[1] = Jp[j*COORD_DIM+2][k] * normal[j*COORD_DIM+0][k] - Jp[j*COORD_DIM+0][k] * normal[j*COORD_DIM+2][k];
 | 
											
												
													
														|  | 
 |  | +              Jxn[2] = Jp[j*COORD_DIM+0][k] * normal[j*COORD_DIM+1][k] - Jp[j*COORD_DIM+1][k] * normal[j*COORD_DIM+0][k];
 | 
											
												
													
														|  | 
 |  | +              S.Bt0[j*COORD_DIM+0][k] += 0.5 * Jxn[0];
 | 
											
												
													
														|  | 
 |  | +              S.Bt0[j*COORD_DIM+1][k] += 0.5 * Jxn[1];
 | 
											
												
													
														|  | 
 |  | +              S.Bt0[j*COORD_DIM+2][k] += 0.5 * Jxn[2];
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +              Jxn[0] = Jt[j*COORD_DIM+1][k] * normal[j*COORD_DIM+2][k] - Jt[j*COORD_DIM+2][k] * normal[j*COORD_DIM+1][k];
 | 
											
												
													
														|  | 
 |  | +              Jxn[1] = Jt[j*COORD_DIM+2][k] * normal[j*COORD_DIM+0][k] - Jt[j*COORD_DIM+0][k] * normal[j*COORD_DIM+2][k];
 | 
											
												
													
														|  | 
 |  | +              Jxn[2] = Jt[j*COORD_DIM+0][k] * normal[j*COORD_DIM+1][k] - Jt[j*COORD_DIM+1][k] * normal[j*COORD_DIM+0][k];
 | 
											
												
													
														|  | 
 |  | +              S.Bp0[j*COORD_DIM+0][k] += 0.5 * Jxn[0];
 | 
											
												
													
														|  | 
 |  | +              S.Bp0[j*COORD_DIM+1][k] += 0.5 * Jxn[1];
 | 
											
												
													
														|  | 
 |  | +              S.Bp0[j*COORD_DIM+2][k] += 0.5 * Jxn[2];
 | 
											
												
													
														|  | 
 |  | +            }
 | 
											
												
													
														|  | 
 |  | +          }
 | 
											
												
													
														|  |          }
 |  |          }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |          compute_invA(S.sigma, S.alpha, S.beta, S, flux_tor_[i], flux_pol_[i], comm);
 |  |          compute_invA(S.sigma, S.alpha, S.beta, S, flux_tor_[i], flux_pol_[i], comm);
 | 
											
										
											
												
													
														|  | @@ -5581,7 +5613,9 @@ template <class Real, Integer ORDER=10> class Stellarator {
 | 
											
												
													
														|  |  };
 |  |  };
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  template <class Real, Integer ORDER=10> class MHDEquilib {
 |  |  template <class Real, Integer ORDER=10> class MHDEquilib {
 | 
											
												
													
														|  | -    static constexpr Integer fourier_upsample = 4;
 |  | 
 | 
											
												
													
														|  | 
 |  | +    static constexpr Integer fourier_dim0 = 50*10*4;
 | 
											
												
													
														|  | 
 |  | +    static constexpr Integer fourier_dim1 = 10*10*4;
 | 
											
												
													
														|  | 
 |  | +    //static constexpr Integer fourier_upsample = 4;
 | 
											
												
													
														|  |      static constexpr Integer COORD_DIM = 3;
 |  |      static constexpr Integer COORD_DIM = 3;
 | 
											
												
													
														|  |      static constexpr Integer ELEM_DIM = COORD_DIM-1;
 |  |      static constexpr Integer ELEM_DIM = COORD_DIM-1;
 | 
											
												
													
														|  |      using ElemBasis = Basis<Real, ELEM_DIM, ORDER>;
 |  |      using ElemBasis = Basis<Real, ELEM_DIM, ORDER>;
 | 
											
										
											
												
													
														|  | @@ -5712,8 +5746,8 @@ template <class Real, Integer ORDER=10> class MHDEquilib {
 | 
											
												
													
														|  |          fft_r2c.Execute(X_, coeff);
 |  |          fft_r2c.Execute(X_, coeff);
 | 
											
												
													
														|  |          for (long t = 0; t < Nt; t++) {
 |  |          for (long t = 0; t < Nt; t++) {
 | 
											
												
													
														|  |            for (long p = 0; p < Np; p++) {
 |  |            for (long p = 0; p < Np; p++) {
 | 
											
												
													
														|  | -            Real tt = (t - (t > Nt / 2 ? Nt : 0)) / (Real)(Nt / 2);
 |  | 
 | 
											
												
													
														|  | -            Real pp = p / (Real)Np;
 |  | 
 | 
											
												
													
														|  | 
 |  | +            Real tt = (t - (t > Nt / 2 ? Nt : 0)) * (2*Np/(Real)Nt);
 | 
											
												
													
														|  | 
 |  | +            Real pp = p;
 | 
											
												
													
														|  |              Real f = filter_fn(tt*tt+pp*pp, sigma);
 |  |              Real f = filter_fn(tt*tt+pp*pp, sigma);
 | 
											
												
													
														|  |              coeff[(t * Np + p) * 2 + 0] *= f;
 |  |              coeff[(t * Np + p) * 2 + 0] *= f;
 | 
											
												
													
														|  |              coeff[(t * Np + p) * 2 + 1] *= f;
 |  |              coeff[(t * Np + p) * 2 + 1] *= f;
 | 
											
										
											
												
													
														|  | @@ -5724,39 +5758,101 @@ template <class Real, Integer ORDER=10> class MHDEquilib {
 | 
											
												
													
														|  |      };
 |  |      };
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      static void fourier_print_spectrum(const Vector<Real>& X, long Nt_, long Np_) {
 |  |      static void fourier_print_spectrum(const Vector<Real>& X, long Nt_, long Np_) {
 | 
											
												
													
														|  | -      long dof = X.Dim() / (Nt_ * Np_);
 |  | 
 | 
											
												
													
														|  | -      SCTL_ASSERT(X.Dim() == dof * Nt_ * Np_);
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -      FFT<Real> fft_r2c, fft_c2r;
 |  | 
 | 
											
												
													
														|  | -      StaticArray<Long, 2> fft_dim = {Nt_, Np_};
 |  | 
 | 
											
												
													
														|  | -      fft_r2c.Setup(FFT_Type::R2C, 1, Vector<Long>(2, fft_dim, false), omp_get_max_threads());
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -      long Nt = Nt_;
 |  | 
 | 
											
												
													
														|  | -      long Np = fft_r2c.Dim(1) / (Nt * 2);
 |  | 
 | 
											
												
													
														|  | -      SCTL_ASSERT(fft_r2c.Dim(1) == Nt * Np * 2);
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -      Vector<Real> coeff(fft_r2c.Dim(1));
 |  | 
 | 
											
												
													
														|  | -      Vector<Real> spectrum(20); spectrum = 0;
 |  | 
 | 
											
												
													
														|  | -      for (long k = 0; k < dof; k++) {
 |  | 
 | 
											
												
													
														|  | -        const Vector<Real> X_(Nt_*Np_, (Iterator<Real>)X.begin() + k*Nt_*Np_, false);
 |  | 
 | 
											
												
													
														|  | -        fft_r2c.Execute(X_, coeff);
 |  | 
 | 
											
												
													
														|  | -        for (long t = 0; t < Nt; t++) {
 |  | 
 | 
											
												
													
														|  | -          for (long p = 0; p < Np; p++) {
 |  | 
 | 
											
												
													
														|  | -            Real tt = (t - (t > Nt / 2 ? Nt : 0)) / (Real)(Nt / 2);
 |  | 
 | 
											
												
													
														|  | -            Real pp = p / (Real)Np;
 |  | 
 | 
											
												
													
														|  | -            Long freq = (Long)(sqrt<Real>(tt*tt+pp*pp)*spectrum.Dim());
 |  | 
 | 
											
												
													
														|  | -            if (freq<20) spectrum[freq] += coeff[(t*Np+p)*2+0]*coeff[(t*Np+p)*2+0];
 |  | 
 | 
											
												
													
														|  | -            if (freq<20) spectrum[freq] += coeff[(t*Np+p)*2+1]*coeff[(t*Np+p)*2+1];
 |  | 
 | 
											
												
													
														|  | -          }
 |  | 
 | 
											
												
													
														|  | 
 |  | +    //  long dof = X.Dim() / (Nt_ * Np_);
 | 
											
												
													
														|  | 
 |  | +    //  SCTL_ASSERT(X.Dim() == dof * Nt_ * Np_);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    //  FFT<Real> fft_r2c, fft_c2r;
 | 
											
												
													
														|  | 
 |  | +    //  StaticArray<Long, 2> fft_dim = {Nt_, Np_};
 | 
											
												
													
														|  | 
 |  | +    //  fft_r2c.Setup(FFT_Type::R2C, 1, Vector<Long>(2, fft_dim, false), omp_get_max_threads());
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    //  long Nt = Nt_;
 | 
											
												
													
														|  | 
 |  | +    //  long Np = fft_r2c.Dim(1) / (Nt * 2);
 | 
											
												
													
														|  | 
 |  | +    //  SCTL_ASSERT(fft_r2c.Dim(1) == Nt * Np * 2);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    //  Vector<Real> coeff(fft_r2c.Dim(1));
 | 
											
												
													
														|  | 
 |  | +    //  Vector<Real> spectrum(200); spectrum = 0;
 | 
											
												
													
														|  | 
 |  | +    //  for (long k = 0; k < dof; k++) {
 | 
											
												
													
														|  | 
 |  | +    //    const Vector<Real> X_(Nt_*Np_, (Iterator<Real>)X.begin() + k*Nt_*Np_, false);
 | 
											
												
													
														|  | 
 |  | +    //    fft_r2c.Execute(X_, coeff);
 | 
											
												
													
														|  | 
 |  | +    //    for (long t = 0; t < Nt; t++) {
 | 
											
												
													
														|  | 
 |  | +    //      for (long p = 0; p < Np; p++) {
 | 
											
												
													
														|  | 
 |  | +    //        Real tt = (t - (t > Nt / 2 ? Nt : 0)) / (Real)(Nt / 2);
 | 
											
												
													
														|  | 
 |  | +    //        Real pp = p / (Real)Np;
 | 
											
												
													
														|  | 
 |  | +    //        Long freq = (Long)(sqrt<Real>(tt*tt+pp*pp)*spectrum.Dim());
 | 
											
												
													
														|  | 
 |  | +    //        if (freq<spectrum.Dim()) spectrum[freq] += coeff[(t*Np+p)*2+0]*coeff[(t*Np+p)*2+0];
 | 
											
												
													
														|  | 
 |  | +    //        if (freq<spectrum.Dim()) spectrum[freq] += coeff[(t*Np+p)*2+1]*coeff[(t*Np+p)*2+1];
 | 
											
												
													
														|  | 
 |  | +    //      }
 | 
											
												
													
														|  | 
 |  | +    //    }
 | 
											
												
													
														|  | 
 |  | +    //  }
 | 
											
												
													
														|  | 
 |  | +    //  for (Long i = 0; i < spectrum.Dim(); i++) {
 | 
											
												
													
														|  | 
 |  | +    //    spectrum[i] = log<Real>(sqrt<Real>(spectrum[i]))/log<Real>(10.0);
 | 
											
												
													
														|  | 
 |  | +    //  }
 | 
											
												
													
														|  | 
 |  | +    //  std::cout<<"spectrum = "<<spectrum<<'\n';
 | 
											
												
													
														|  | 
 |  | +    };
 | 
											
												
													
														|  | 
 |  | +    static void fourier_print_spectrum(std::string var_name, const sctl::Vector<Real>& B0, sctl::Long Nt0, sctl::Long Np0) {
 | 
											
												
													
														|  | 
 |  | +      auto Resample = [](const sctl::Vector<Real>& B, long Nt, long Np, long Nt0, long Np0) {
 | 
											
												
													
														|  | 
 |  | +        sctl::Vector<Real> B0;
 | 
											
												
													
														|  | 
 |  | +        biest::SurfaceOp<Real>::Upsample(B,Nt,Np, B0,Nt0,Np0);
 | 
											
												
													
														|  | 
 |  | +        return B0;
 | 
											
												
													
														|  | 
 |  | +      };
 | 
											
												
													
														|  | 
 |  | +      auto max_rel_err = [](const sctl::Vector<Real> A, const sctl::Vector<Real> B) {
 | 
											
												
													
														|  | 
 |  | +        SCTL_ASSERT(A.Dim() == B.Dim());
 | 
											
												
													
														|  | 
 |  | +        Real max_err = 0;
 | 
											
												
													
														|  | 
 |  | +        Real max_val = 1e-20;
 | 
											
												
													
														|  | 
 |  | +        for (sctl::Long i = 0; i < A.Dim(); i++) {
 | 
											
												
													
														|  | 
 |  | +          max_err = std::max<Real>(max_err, fabs(A[i]-B[i]));
 | 
											
												
													
														|  | 
 |  | +          max_val = std::max<Real>(max_val, fabs(A[i]));
 | 
											
												
													
														|  |          }
 |  |          }
 | 
											
												
													
														|  | -      }
 |  | 
 | 
											
												
													
														|  | -      for (Long i = 0; i < spectrum.Dim(); i++) {
 |  | 
 | 
											
												
													
														|  | -        spectrum[i] = log<Real>(sqrt<Real>(spectrum[i]))/log<Real>(10.0);
 |  | 
 | 
											
												
													
														|  | -      }
 |  | 
 | 
											
												
													
														|  | -      std::cout<<"spectrum = "<<spectrum<<'\n';
 |  | 
 | 
											
												
													
														|  | 
 |  | +        return max_err/max_val;
 | 
											
												
													
														|  | 
 |  | +      };
 | 
											
												
													
														|  | 
 |  | +      auto max_err = [](const sctl::Vector<Real> A, const sctl::Vector<Real> B) {
 | 
											
												
													
														|  | 
 |  | +        SCTL_ASSERT(A.Dim() == B.Dim());
 | 
											
												
													
														|  | 
 |  | +        Real max_err = 0;
 | 
											
												
													
														|  | 
 |  | +        for (sctl::Long i = 0; i < A.Dim(); i++) {
 | 
											
												
													
														|  | 
 |  | +          max_err = std::max<Real>(max_err, fabs(A[i]-B[i]));
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +        return max_err;
 | 
											
												
													
														|  | 
 |  | +      };
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      std::cout<<var_name<<"=[";
 | 
											
												
													
														|  | 
 |  | +      for (sctl::Long i = 1; i < 140; i++) {
 | 
											
												
													
														|  | 
 |  | +        sctl::Long Nt1 = 6*i, Np1 = i;
 | 
											
												
													
														|  | 
 |  | +        auto B1 = Resample(Resample(B0, Nt0,Np0, Nt1,Np1), Nt1,Np1, Nt0,Np0);
 | 
											
												
													
														|  | 
 |  | +        std::cout<<log(max_err(B0, B1))/log(10)<<' ';
 | 
											
												
													
														|  | 
 |  | +      }
 | 
											
												
													
														|  | 
 |  | +      std::cout<<"];\n";
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      //if (0) {
 | 
											
												
													
														|  | 
 |  | +      //  auto B1 = Resample(B0, Nt0,Np0, 70*30,14*30);
 | 
											
												
													
														|  | 
 |  | +      //  B1.Write(var_name.c_str());
 | 
											
												
													
														|  | 
 |  | +      //} else {
 | 
											
												
													
														|  | 
 |  | +      //  auto B1 = Resample(B0, Nt0,Np0, 70*30,14*30);
 | 
											
												
													
														|  | 
 |  | +      //  sctl::Vector<Real> B2; B2.Read(var_name.c_str());
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      //  Real max_err = 0, max_val = 0;
 | 
											
												
													
														|  | 
 |  | +      //  for (sctl::Long i = 0; i < B1.Dim(); i++) {
 | 
											
												
													
														|  | 
 |  | +      //    max_err = std::max<Real>(max_err, fabs(B1[i]-B2[i]));
 | 
											
												
													
														|  | 
 |  | +      //    max_val = std::max<Real>(max_val, fabs(B2[i]));
 | 
											
												
													
														|  | 
 |  | +      //  }
 | 
											
												
													
														|  | 
 |  | +      //  std::cout<<"Error "<<var_name<<" = "<<max_err/max_val<<'\n';
 | 
											
												
													
														|  | 
 |  | +      //}
 | 
											
												
													
														|  |      };
 |  |      };
 | 
											
												
													
														|  | 
 |  | +    static void fourier_print_spectrum(std::string var_name, const Vector<Real>& X_, Stellarator<Real,ORDER> S_) {
 | 
											
												
													
														|  | 
 |  | +      Long dof = X_.Dim()/(S_.Nsurf()*fourier_dim0*fourier_dim1);
 | 
											
												
													
														|  | 
 |  | +      SCTL_ASSERT(dof * (S_.Nsurf()*fourier_dim0*fourier_dim1) == X_.Dim());
 | 
											
												
													
														|  | 
 |  | +      for (Long i = 0; i < S_.Nsurf(); i++) {
 | 
											
												
													
														|  | 
 |  | +        const Long Mt = S_.NTor(i);
 | 
											
												
													
														|  | 
 |  | +        const Long Mp = S_.NPol(i);
 | 
											
												
													
														|  | 
 |  | +        const Long offset = S_.ElemDsp(i);
 | 
											
												
													
														|  | 
 |  | +        const Long Nt = fourier_dim0;
 | 
											
												
													
														|  | 
 |  | +        const Long Np = fourier_dim1;
 | 
											
												
													
														|  | 
 |  | +        const Vector<Real> X(dof*Nt*Np, (Iterator<Real>)X_.begin() + dof * i * (fourier_dim0*fourier_dim1), false);
 | 
											
												
													
														|  | 
 |  | +        fourier_print_spectrum(var_name+std::to_string(i),X,Nt,Np);
 | 
											
												
													
														|  | 
 |  | +      }
 | 
											
												
													
														|  | 
 |  | +      std::cout<<"\n";
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -    static void filter(const Stellarator<Real,ORDER>& S, const Comm& comm, Vector<ElemBasis>& f, Real sigma) {
 |  | 
 | 
											
												
													
														|  | 
 |  | +    static void filter_deprecated(const Stellarator<Real,ORDER>& S, const Comm& comm, Vector<ElemBasis>& f, Real sigma) {
 | 
											
												
													
														|  |        Long dof = f.Dim() / S.NElem();
 |  |        Long dof = f.Dim() / S.NElem();
 | 
											
												
													
														|  |        SCTL_ASSERT(f.Dim() == S.NElem() * dof);
 |  |        SCTL_ASSERT(f.Dim() == S.NElem() * dof);
 | 
											
												
													
														|  |        for (Long i = 0; i < S.Nsurf()-1; i++) {
 |  |        for (Long i = 0; i < S.Nsurf()-1; i++) {
 | 
											
										
											
												
													
														|  | @@ -5780,16 +5876,16 @@ template <class Real, Integer ORDER=10> class MHDEquilib {
 | 
											
												
													
														|  |        const Long dof = f.Dim() / Nelem;
 |  |        const Long dof = f.Dim() / Nelem;
 | 
											
												
													
														|  |        SCTL_ASSERT(Nelem * dof == f.Dim());
 |  |        SCTL_ASSERT(Nelem * dof == f.Dim());
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -      Vector<Real> f_fourier(dof * Nelem * (ORDER*ORDER*fourier_upsample*fourier_upsample));
 |  | 
 | 
											
												
													
														|  | 
 |  | +      Vector<Real> f_fourier(dof * S.Nsurf() * (fourier_dim0*fourier_dim1));
 | 
											
												
													
														|  |        for (Long i = 0; i < S.Nsurf(); i++) {
 |  |        for (Long i = 0; i < S.Nsurf(); i++) {
 | 
											
												
													
														|  |          const Long Mt = S.NTor(i);
 |  |          const Long Mt = S.NTor(i);
 | 
											
												
													
														|  |          const Long Mp = S.NPol(i);
 |  |          const Long Mp = S.NPol(i);
 | 
											
												
													
														|  |          const Long offset = S.ElemDsp(i);
 |  |          const Long offset = S.ElemDsp(i);
 | 
											
												
													
														|  | -        const Long Nt = Mt * ORDER * fourier_upsample;
 |  | 
 | 
											
												
													
														|  | -        const Long Np = Mp * ORDER * fourier_upsample;
 |  | 
 | 
											
												
													
														|  | 
 |  | +        const Long Nt = fourier_dim0;
 | 
											
												
													
														|  | 
 |  | +        const Long Np = fourier_dim1;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |          const Vector<ElemBasis> f_(Mt*Mp*dof, (Iterator<ElemBasis>)f.begin() + offset*dof, false);
 |  |          const Vector<ElemBasis> f_(Mt*Mp*dof, (Iterator<ElemBasis>)f.begin() + offset*dof, false);
 | 
											
												
													
														|  | -        Vector<Real> f_fourier_(dof*Nt*Np, f_fourier.begin() + dof*offset * (ORDER*ORDER*fourier_upsample*fourier_upsample), false);
 |  | 
 | 
											
												
													
														|  | 
 |  | +        Vector<Real> f_fourier_(dof*Nt*Np, f_fourier.begin() + dof*i * (fourier_dim0*fourier_dim1), false);
 | 
											
												
													
														|  |          f_fourier_ = cheb2grid(f_, Mt, Mp, Nt, Np);
 |  |          f_fourier_ = cheb2grid(f_, Mt, Mp, Nt, Np);
 | 
											
												
													
														|  |          SCTL_ASSERT(f_fourier_.Dim() == dof*Nt*Np);
 |  |          SCTL_ASSERT(f_fourier_.Dim() == dof*Nt*Np);
 | 
											
												
													
														|  |        }
 |  |        }
 | 
											
										
											
												
													
														|  | @@ -5798,26 +5894,26 @@ template <class Real, Integer ORDER=10> class MHDEquilib {
 | 
											
												
													
														|  |      static Vector<ElemBasis> grid2cheb(const Stellarator<Real,ORDER>& S, const Vector<Real>& f_fourier) {
 |  |      static Vector<ElemBasis> grid2cheb(const Stellarator<Real,ORDER>& S, const Vector<Real>& f_fourier) {
 | 
											
												
													
														|  |        const Long Nnodes = ElemBasis::Size();
 |  |        const Long Nnodes = ElemBasis::Size();
 | 
											
												
													
														|  |        const Long Nelem = S.NElem();
 |  |        const Long Nelem = S.NElem();
 | 
											
												
													
														|  | -      const Long dof = f_fourier.Dim() / (Nelem * (ORDER*ORDER*fourier_upsample*fourier_upsample));
 |  | 
 | 
											
												
													
														|  | -      SCTL_ASSERT(dof * Nelem * (ORDER*ORDER*fourier_upsample*fourier_upsample) == f_fourier.Dim());
 |  | 
 | 
											
												
													
														|  | 
 |  | +      const Long dof = f_fourier.Dim() / (S.Nsurf() * (fourier_dim0*fourier_dim1));
 | 
											
												
													
														|  | 
 |  | +      SCTL_ASSERT(dof * (S.Nsurf() * (fourier_dim0*fourier_dim1)) == f_fourier.Dim());
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |        Vector<ElemBasis> f(Nelem * dof);
 |  |        Vector<ElemBasis> f(Nelem * dof);
 | 
											
												
													
														|  |        for (Long i = 0; i < S.Nsurf(); i++) {
 |  |        for (Long i = 0; i < S.Nsurf(); i++) {
 | 
											
												
													
														|  |          const Long Mt = S.NTor(i);
 |  |          const Long Mt = S.NTor(i);
 | 
											
												
													
														|  |          const Long Mp = S.NPol(i);
 |  |          const Long Mp = S.NPol(i);
 | 
											
												
													
														|  |          const Long offset = S.ElemDsp(i);
 |  |          const Long offset = S.ElemDsp(i);
 | 
											
												
													
														|  | -        const Long Nt = Mt * ORDER * fourier_upsample;
 |  | 
 | 
											
												
													
														|  | -        const Long Np = Mp * ORDER * fourier_upsample;
 |  | 
 | 
											
												
													
														|  | 
 |  | +        const Long Nt = fourier_dim0;
 | 
											
												
													
														|  | 
 |  | +        const Long Np = fourier_dim1;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |          Vector<ElemBasis> f_(Mt*Mp*dof, f.begin() + offset*dof, false);
 |  |          Vector<ElemBasis> f_(Mt*Mp*dof, f.begin() + offset*dof, false);
 | 
											
												
													
														|  | -        const Vector<Real> f_fourier_(dof*Nt*Np, (Iterator<Real>)f_fourier.begin() + dof*offset * (ORDER*ORDER*fourier_upsample*fourier_upsample), false);
 |  | 
 | 
											
												
													
														|  | 
 |  | +        const Vector<Real> f_fourier_(dof*Nt*Np, (Iterator<Real>)f_fourier.begin() + dof*i * (fourier_dim0*fourier_dim1), false);
 | 
											
												
													
														|  |          f_ = grid2cheb(f_fourier_, Nt, Np, Mt, Mp);
 |  |          f_ = grid2cheb(f_fourier_, Nt, Np, Mt, Mp);
 | 
											
												
													
														|  |          SCTL_ASSERT(f_.Dim() == Mt*Mp*dof);
 |  |          SCTL_ASSERT(f_.Dim() == Mt*Mp*dof);
 | 
											
												
													
														|  |        }
 |  |        }
 | 
											
												
													
														|  |        return f;
 |  |        return f;
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -    template <class Real, class GradOp> static Long GradientDescent3(GradOp& grad_op, Eigen::VectorXd& x, Real& fx, Long max_iter, Real tol) {
 |  | 
 | 
											
												
													
														|  | 
 |  | +    template <class Real, class GradOp> static Long GradientDescent3(GradOp& grad_fn, Eigen::VectorXd& x, Real& fx, Long max_iter, Real tol) {
 | 
											
												
													
														|  |        Real dt = 0.1;
 |  |        Real dt = 0.1;
 | 
											
												
													
														|  |        Real step_tol = 1e-1;
 |  |        Real step_tol = 1e-1;
 | 
											
												
													
														|  |        for (Long iter = 0; iter < max_iter; iter++) {
 |  |        for (Long iter = 0; iter < max_iter; iter++) {
 | 
											
										
											
												
													
														|  | @@ -5839,7 +5935,7 @@ template <class Real, Integer ORDER=10> class MHDEquilib {
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |          Real error;
 |  |          Real error;
 | 
											
												
													
														|  |          Eigen::VectorXd x_(x.size());
 |  |          Eigen::VectorXd x_(x.size());
 | 
											
												
													
														|  | -        time_step(&x_, dt, x, grad_op, &error);
 |  | 
 | 
											
												
													
														|  | 
 |  | +        time_step(&x_, dt, x, grad_fn, &error);
 | 
											
												
													
														|  |          if (error > 2.0 * step_tol) {
 |  |          if (error > 2.0 * step_tol) {
 | 
											
												
													
														|  |            dt *= 0.5;
 |  |            dt *= 0.5;
 | 
											
												
													
														|  |          } else {
 |  |          } else {
 | 
											
										
											
												
													
														|  | @@ -5851,7 +5947,7 @@ template <class Real, Integer ORDER=10> class MHDEquilib {
 | 
											
												
													
														|  |        return max_iter;
 |  |        return max_iter;
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -    template <class Real, class GradOp> static Long GradientDescent2(GradOp& grad_op, Eigen::VectorXd& x, Real& fx, Long max_iter, Real tol) {
 |  | 
 | 
											
												
													
														|  | 
 |  | +    template <class Real, class GradOp> static Long GradientDescent2(GradOp& grad_fn, Eigen::VectorXd& x, Real& fx, Long max_iter, Real tol) {
 | 
											
												
													
														|  |        Real dt = 0.1;
 |  |        Real dt = 0.1;
 | 
											
												
													
														|  |        Real step_tol = 1e-1;
 |  |        Real step_tol = 1e-1;
 | 
											
												
													
														|  |        for (Long iter = 0; iter < max_iter; iter++) {
 |  |        for (Long iter = 0; iter < max_iter; iter++) {
 | 
											
										
											
												
													
														|  | @@ -5878,7 +5974,7 @@ template <class Real, Integer ORDER=10> class MHDEquilib {
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |          Real error;
 |  |          Real error;
 | 
											
												
													
														|  |          Eigen::VectorXd x_(x.size());
 |  |          Eigen::VectorXd x_(x.size());
 | 
											
												
													
														|  | -        time_step(&x_, dt, x, grad_op, &error);
 |  | 
 | 
											
												
													
														|  | 
 |  | +        time_step(&x_, dt, x, grad_fn, &error);
 | 
											
												
													
														|  |          if (error > 2.0 * step_tol) {
 |  |          if (error > 2.0 * step_tol) {
 | 
											
												
													
														|  |            dt *= 0.5;
 |  |            dt *= 0.5;
 | 
											
												
													
														|  |          } else {
 |  |          } else {
 | 
											
										
											
												
													
														|  | @@ -5890,7 +5986,7 @@ template <class Real, Integer ORDER=10> class MHDEquilib {
 | 
											
												
													
														|  |        return max_iter;
 |  |        return max_iter;
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -    template <class Real, class GradOp> static Long GradientDescent2_(GradOp& grad_op, Eigen::VectorXd& x, Real& fx, Long max_iter, Real tol) {
 |  | 
 | 
											
												
													
														|  | 
 |  | +    template <class Real, class GradOp> static Long GradientDescent2_(GradOp& grad_fn, Eigen::VectorXd& x, Real& fx, Long max_iter, Real tol) {
 | 
											
												
													
														|  |        Real dt_ = 0, fx_ = 0;
 |  |        Real dt_ = 0, fx_ = 0;
 | 
											
												
													
														|  |        Eigen::VectorXd x_ = x;
 |  |        Eigen::VectorXd x_ = x;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
										
											
												
													
														|  | @@ -5898,7 +5994,7 @@ template <class Real, Integer ORDER=10> class MHDEquilib {
 | 
											
												
													
														|  |        for (Long iter = 0; iter < max_iter; iter++) {
 |  |        for (Long iter = 0; iter < max_iter; iter++) {
 | 
											
												
													
														|  |          Eigen::VectorXd grad0(x.size()), grad1(x.size()), grad2(x.size());
 |  |          Eigen::VectorXd grad0(x.size()), grad1(x.size()), grad2(x.size());
 | 
											
												
													
														|  |          fx_ = fx;
 |  |          fx_ = fx;
 | 
											
												
													
														|  | -        fx = grad_op(x, grad0);
 |  | 
 | 
											
												
													
														|  | 
 |  | +        fx = grad_fn(x, grad0);
 | 
											
												
													
														|  |          if (fx < tol) return iter;
 |  |          if (fx < tol) return iter;
 | 
											
												
													
														|  |          if (iter && fx > fx_) {
 |  |          if (iter && fx > fx_) {
 | 
											
												
													
														|  |            x = x_;
 |  |            x = x_;
 | 
											
										
											
												
													
														|  | @@ -5911,10 +6007,10 @@ template <class Real, Integer ORDER=10> class MHDEquilib {
 | 
											
												
													
														|  |          }
 |  |          }
 | 
											
												
													
														|  |          { // Update dt
 |  |          { // Update dt
 | 
											
												
													
														|  |            Real fx1, fx2;
 |  |            Real fx1, fx2;
 | 
											
												
													
														|  | -          fx1 = grad_op(x - grad0 * dt * 0.50, grad1);
 |  | 
 | 
											
												
													
														|  | -          fx1 = grad_op(x - grad0 * dt * 0.25 - grad1 * dt * 0.25, grad1);
 |  | 
 | 
											
												
													
														|  | -          fx2 = grad_op(x - grad1 * dt, grad2);
 |  | 
 | 
											
												
													
														|  | -          fx2 = grad_op(x - grad0 * dt * (1.0/6.0) - grad1 * dt * (2.0/3.0) - grad2 * dt * (1.0/6.0), grad2);
 |  | 
 | 
											
												
													
														|  | 
 |  | +          fx1 = grad_fn(x - grad0 * dt * 0.50, grad1);
 | 
											
												
													
														|  | 
 |  | +          fx1 = grad_fn(x - grad0 * dt * 0.25 - grad1 * dt * 0.25, grad1);
 | 
											
												
													
														|  | 
 |  | +          fx2 = grad_fn(x - grad1 * dt, grad2);
 | 
											
												
													
														|  | 
 |  | +          fx2 = grad_fn(x - grad0 * dt * (1.0/6.0) - grad1 * dt * (2.0/3.0) - grad2 * dt * (1.0/6.0), grad2);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |            Real s;
 |  |            Real s;
 | 
											
												
													
														|  |            { // Calculate optimal step size dt
 |  |            { // Calculate optimal step size dt
 | 
											
										
											
												
													
														|  | @@ -5937,17 +6033,17 @@ template <class Real, Integer ORDER=10> class MHDEquilib {
 | 
											
												
													
														|  |        return max_iter;
 |  |        return max_iter;
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -    template <class Real, class GradOp> static Long GradientDescent(GradOp& grad_op, Eigen::VectorXd& x, Real& fx, Long max_iter, Real tol) {
 |  | 
 | 
											
												
													
														|  | -      Real dt = 0.1;
 |  | 
 | 
											
												
													
														|  | 
 |  | +    template <class Real, class GradOp> static Long GradientDescent(GradOp& grad_fn, Eigen::VectorXd& x, Real& fx, Long max_iter, Real tol) {
 | 
											
												
													
														|  | 
 |  | +      Real dt = 0.192081;
 | 
											
												
													
														|  |        for (Long iter = 0; iter < max_iter; iter++) {
 |  |        for (Long iter = 0; iter < max_iter; iter++) {
 | 
											
												
													
														|  |          Eigen::VectorXd grad(x.size());
 |  |          Eigen::VectorXd grad(x.size());
 | 
											
												
													
														|  | -        fx = grad_op(x, grad);
 |  | 
 | 
											
												
													
														|  | 
 |  | +        fx = grad_fn(x, grad);
 | 
											
												
													
														|  |          { // Update dt
 |  |          { // Update dt
 | 
											
												
													
														|  |            Eigen::VectorXd grad_(x.size());
 |  |            Eigen::VectorXd grad_(x.size());
 | 
											
												
													
														|  |            Eigen::VectorXd x1 = x - grad * dt * 0.5;
 |  |            Eigen::VectorXd x1 = x - grad * dt * 0.5;
 | 
											
												
													
														|  |            Eigen::VectorXd x2 = x - grad * dt * 1.0;
 |  |            Eigen::VectorXd x2 = x - grad * dt * 1.0;
 | 
											
												
													
														|  | -          Real fx1 = grad_op(x1, grad_);
 |  | 
 | 
											
												
													
														|  | -          Real fx2 = grad_op(x2, grad_);
 |  | 
 | 
											
												
													
														|  | 
 |  | +          Real fx1 = grad_fn(x1, grad_);
 | 
											
												
													
														|  | 
 |  | +          Real fx2 = grad_fn(x2, grad_);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |            { // Calculate optimal step size dt
 |  |            { // Calculate optimal step size dt
 | 
											
												
													
														|  |              Real a = 2*fx - 4*fx1 + 2*fx2;
 |  |              Real a = 2*fx - 4*fx1 + 2*fx2;
 | 
											
										
											
												
													
														|  | @@ -5970,13 +6066,298 @@ template <class Real, Integer ORDER=10> class MHDEquilib {
 | 
											
												
													
														|  |        return max_iter;
 |  |        return max_iter;
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | 
 |  | +    template <class ValueType> static ValueType QuadraticInterp(Real t, const ValueType& v0, const ValueType& v1, const ValueType& v2, Real t0, Real t1, Real t2) {
 | 
											
												
													
														|  | 
 |  | +      ValueType v = v0 * (((t-t1)*(t-t2))/((t0-t1)*(t0-t2)));
 | 
											
												
													
														|  | 
 |  | +      v += v1 * (((t-t0)*(t-t2))/((t1-t0)*(t1-t2)));
 | 
											
												
													
														|  | 
 |  | +      v += v2 * (((t-t0)*(t-t1))/((t2-t0)*(t2-t1)));
 | 
											
												
													
														|  | 
 |  | +      return v;
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    template <class Real, class GradOp> static Long GradientDescentNew(GradOp& grad_fn, Eigen::VectorXd& x0, Real& fx, Long max_iter, Real tol) {
 | 
											
												
													
														|  | 
 |  | +      auto compute_inner_prod = [](const Eigen::VectorXd& A, const Eigen::VectorXd& B) {
 | 
											
												
													
														|  | 
 |  | +        Real sum = 0;
 | 
											
												
													
														|  | 
 |  | +        Long N = A.size();
 | 
											
												
													
														|  | 
 |  | +        SCTL_ASSERT(B.size() == N);
 | 
											
												
													
														|  | 
 |  | +        for (Long i = 0; i < N; i++) sum += A[i] * B[i];
 | 
											
												
													
														|  | 
 |  | +        return sum;
 | 
											
												
													
														|  | 
 |  | +      };
 | 
											
												
													
														|  | 
 |  | +      auto compute_dt_scale = [&compute_inner_prod](const Eigen::VectorXd& x, const Eigen::VectorXd& y){
 | 
											
												
													
														|  | 
 |  | +        Real dot_prod = compute_inner_prod(x, y) / sqrt<Real>(compute_inner_prod(x,x)*compute_inner_prod(y,y));
 | 
											
												
													
														|  | 
 |  | +        return 0.05 / sqrt<Real>(1-dot_prod*dot_prod);
 | 
											
												
													
														|  | 
 |  | +      };
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      Eigen::VectorXd grad, x = x0;
 | 
											
												
													
														|  | 
 |  | +      Real g = grad_fn(x, grad);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      Real t = 0, dt = -0.1;
 | 
											
												
													
														|  | 
 |  | +      for (Long j = 0; j < max_iter; j++) {
 | 
											
												
													
														|  | 
 |  | +        Eigen::VectorXd grad0, grad1, grad2;
 | 
											
												
													
														|  | 
 |  | +        Real g0 = grad_fn(x + grad*(dt*0.5) + grad *(dt*0.5), grad0);
 | 
											
												
													
														|  | 
 |  | +        Real g1 = grad_fn(x + grad*(dt*0.5) + grad0*(dt*0.5), grad1);
 | 
											
												
													
														|  | 
 |  | +        Real g2 = grad_fn(x + grad*(dt*0.5) + grad1*(dt*0.5), grad2);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        Eigen::VectorXd grad4, grad3;
 | 
											
												
													
														|  | 
 |  | +        Real c = compute_inner_prod(grad2-grad1,grad2-grad1) / compute_inner_prod(grad1-grad0,grad2-grad1);
 | 
											
												
													
														|  | 
 |  | +        grad3 = (grad2 - grad1*c) * (1/(1-c));
 | 
											
												
													
														|  | 
 |  | +        Real g3 = grad_fn(x + grad*(dt*0.5) + grad3*(dt*0.5), grad4);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        std::cout<<sqrt<Real>(compute_inner_prod(grad -grad4,grad -grad4)/compute_inner_prod(grad4,grad4))<<' ';
 | 
											
												
													
														|  | 
 |  | +        std::cout<<sqrt<Real>(compute_inner_prod(grad -grad3,grad -grad3)/compute_inner_prod(grad4,grad4))<<' ';
 | 
											
												
													
														|  | 
 |  | +        std::cout<<sqrt<Real>(compute_inner_prod(grad -grad2,grad -grad2)/compute_inner_prod(grad4,grad4))<<' ';
 | 
											
												
													
														|  | 
 |  | +        std::cout<<sqrt<Real>(compute_inner_prod(grad -grad1,grad -grad1)/compute_inner_prod(grad4,grad4))<<' ';
 | 
											
												
													
														|  | 
 |  | +        std::cout<<sqrt<Real>(compute_inner_prod(grad -grad0,grad -grad0)/compute_inner_prod(grad4,grad4))<<'\n';
 | 
											
												
													
														|  | 
 |  | +        std::cout<<sqrt<Real>(compute_inner_prod(grad0-grad4,grad0-grad4)/compute_inner_prod(grad4,grad4))<<' ';
 | 
											
												
													
														|  | 
 |  | +        std::cout<<sqrt<Real>(compute_inner_prod(grad0-grad3,grad0-grad3)/compute_inner_prod(grad4,grad4))<<' ';
 | 
											
												
													
														|  | 
 |  | +        std::cout<<sqrt<Real>(compute_inner_prod(grad0-grad2,grad0-grad2)/compute_inner_prod(grad4,grad4))<<' ';
 | 
											
												
													
														|  | 
 |  | +        std::cout<<sqrt<Real>(compute_inner_prod(grad0-grad1,grad0-grad1)/compute_inner_prod(grad4,grad4))<<'\n';
 | 
											
												
													
														|  | 
 |  | +        std::cout<<sqrt<Real>(compute_inner_prod(grad1-grad4,grad1-grad4)/compute_inner_prod(grad4,grad4))<<' ';
 | 
											
												
													
														|  | 
 |  | +        std::cout<<sqrt<Real>(compute_inner_prod(grad1-grad3,grad1-grad3)/compute_inner_prod(grad4,grad4))<<' ';
 | 
											
												
													
														|  | 
 |  | +        std::cout<<sqrt<Real>(compute_inner_prod(grad1-grad2,grad1-grad2)/compute_inner_prod(grad4,grad4))<<'\n';
 | 
											
												
													
														|  | 
 |  | +        std::cout<<sqrt<Real>(compute_inner_prod(grad2-grad4,grad2-grad4)/compute_inner_prod(grad4,grad4))<<' ';
 | 
											
												
													
														|  | 
 |  | +        std::cout<<sqrt<Real>(compute_inner_prod(grad2-grad3,grad2-grad3)/compute_inner_prod(grad4,grad4))<<'\n';
 | 
											
												
													
														|  | 
 |  | +        std::cout<<sqrt<Real>(compute_inner_prod(grad3-grad4,grad3-grad4)/compute_inner_prod(grad4,grad4))<<'\n';
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        Real s0 = sqrt<Real>(compute_inner_prod(grad -grad4,grad -grad4)/compute_inner_prod(grad4,grad4));
 | 
											
												
													
														|  | 
 |  | +        Real s1 = sqrt<Real>(compute_inner_prod(grad0-grad1,grad0-grad1)/compute_inner_prod(grad4,grad4));
 | 
											
												
													
														|  | 
 |  | +        Real s2 = sqrt<Real>(compute_inner_prod(grad1-grad2,grad1-grad2)/compute_inner_prod(grad4,grad4));
 | 
											
												
													
														|  | 
 |  | +        Real s3 = sqrt<Real>(compute_inner_prod(grad3-grad4,grad3-grad4)/compute_inner_prod(grad4,grad4));
 | 
											
												
													
														|  | 
 |  | +        Real dt_scale = (0.1/s0); // 0.5*(s1/s2);
 | 
											
												
													
														|  | 
 |  | +        if (s3 > s2) dt_scale = std::min(0.5, dt_scale);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        std::cout<<s0<<' '<<s1<<' '<<s2<<' '<<s3<<"        dt_scale = "<<dt_scale<<'\n'; ////////////////////
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        if (dt_scale>0.5) {
 | 
											
												
													
														|  | 
 |  | +          t += dt;
 | 
											
												
													
														|  | 
 |  | +          g = g3;
 | 
											
												
													
														|  | 
 |  | +          x = x + grad *(dt*0.5) + grad3*(dt*0.5);
 | 
											
												
													
														|  | 
 |  | +          grad = grad4;
 | 
											
												
													
														|  | 
 |  | +          std::cout<<"iter = "<<j<<"   t = "<<t<<"   g = "<<g<<"   dt = "<<dt<<'\n';
 | 
											
												
													
														|  | 
 |  | +        } else {
 | 
											
												
													
														|  | 
 |  | +          j--;
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +        dt *= dt_scale;
 | 
											
												
													
														|  | 
 |  | +      }
 | 
											
												
													
														|  | 
 |  | +      return 0;
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    template <class Real, class GradOp> static Long GradientDescentNew__(GradOp& grad_fn, Eigen::VectorXd& x, Real& fx, Long max_iter, Real tol) {
 | 
											
												
													
														|  | 
 |  | +      auto compute_inner_prod = [](const Eigen::VectorXd& A, const Eigen::VectorXd& B) {
 | 
											
												
													
														|  | 
 |  | +        Real sum = 0;
 | 
											
												
													
														|  | 
 |  | +        Long N = A.size();
 | 
											
												
													
														|  | 
 |  | +        SCTL_ASSERT(B.size() == N);
 | 
											
												
													
														|  | 
 |  | +        for (Long i = 0; i < N; i++) sum += A[i] * B[i];
 | 
											
												
													
														|  | 
 |  | +        return sum;
 | 
											
												
													
														|  | 
 |  | +      };
 | 
											
												
													
														|  | 
 |  | +      auto compute_dt_scale = [&compute_inner_prod](const Eigen::VectorXd& x, const Eigen::VectorXd& y){
 | 
											
												
													
														|  | 
 |  | +        Real dot_prod = compute_inner_prod(x, y) / sqrt<Real>(compute_inner_prod(x,x)*compute_inner_prod(y,y));
 | 
											
												
													
														|  | 
 |  | +        return 0.05 / sqrt<Real>(1-dot_prod*dot_prod);
 | 
											
												
													
														|  | 
 |  | +      };
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      Eigen::VectorXd x0, grad0, grad_op0;
 | 
											
												
													
														|  | 
 |  | +      Eigen::VectorXd x1, grad1, grad_op1;
 | 
											
												
													
														|  | 
 |  | +      Eigen::VectorXd x2, grad2, grad_op2;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      x0 = x;
 | 
											
												
													
														|  | 
 |  | +      Real t = 0, dt = -0.1;
 | 
											
												
													
														|  | 
 |  | +      for (Long j = 0; j < max_iter; j++) {
 | 
											
												
													
														|  | 
 |  | +        Real g0 = grad_fn(x0, grad0);
 | 
											
												
													
														|  | 
 |  | +        Real g1 = grad_fn(x0 + grad0*(dt*0.1), grad1);
 | 
											
												
													
														|  | 
 |  | +        Real g2 = grad_fn(x0 + grad0*(dt*0.1) + grad1*(dt*0.1), grad2);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        // Fit v = v0 + v1 exp(-alpha * dt)
 | 
											
												
													
														|  | 
 |  | +        auto v1 = (grad1-grad0) * (1/(dt*0.1));
 | 
											
												
													
														|  | 
 |  | +        Real alpha = (sqrt<Real>(compute_inner_prod(grad1-grad0,grad1-grad0))/sqrt<Real>(compute_inner_prod(grad2-grad1,grad2-grad1))-1) / (0.1*dt);
 | 
											
												
													
														|  | 
 |  | +        auto v0 = grad0 - v1;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        x0 = x0 + v0*dt - v1 * ((exp<Real>(-alpha*dt)-1.0)/alpha);
 | 
											
												
													
														|  | 
 |  | +        t += dt;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        std::cout<<"iter = "<<j<<"   t = "<<t<<"   g = "<<g0<<"   dt = "<<dt<<'\n';
 | 
											
												
													
														|  | 
 |  | +      }
 | 
											
												
													
														|  | 
 |  | +      return 0;
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    template <class Real, class GradOp> static Long GradientDescentNew_(GradOp& grad_fn, Eigen::VectorXd& x0, Real& fx, Long max_iter, Real tol) {
 | 
											
												
													
														|  | 
 |  | +      constexpr Long order = 3;
 | 
											
												
													
														|  | 
 |  | +      Eigen::VectorXd x[order], grad[order], grad_op[order];
 | 
											
												
													
														|  | 
 |  | +      Real g[order], t[order];
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      auto compute_inner_prod = [](const Eigen::VectorXd& A, const Eigen::VectorXd& B) {
 | 
											
												
													
														|  | 
 |  | +        Real sum = 0;
 | 
											
												
													
														|  | 
 |  | +        Long N = A.size();
 | 
											
												
													
														|  | 
 |  | +        SCTL_ASSERT(B.size() == N);
 | 
											
												
													
														|  | 
 |  | +        for (Long i = 0; i < N; i++) sum += A[i] * B[i];
 | 
											
												
													
														|  | 
 |  | +        return sum;
 | 
											
												
													
														|  | 
 |  | +      };
 | 
											
												
													
														|  | 
 |  | +      auto compute_dt_scale = [&compute_inner_prod](const Eigen::VectorXd& x, const Eigen::VectorXd& y){
 | 
											
												
													
														|  | 
 |  | +        Real dot_prod = compute_inner_prod(x, y) / sqrt<Real>(compute_inner_prod(x,x)*compute_inner_prod(y,y));
 | 
											
												
													
														|  | 
 |  | +        return 0.05 / sqrt<Real>(1-dot_prod*dot_prod);
 | 
											
												
													
														|  | 
 |  | +      };
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      t[1] = 0;
 | 
											
												
													
														|  | 
 |  | +      x[1] = x0;
 | 
											
												
													
														|  | 
 |  | +      g[1] = grad_fn(x[1], grad[1], &grad_op[1]);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      Real dt = -0.1;
 | 
											
												
													
														|  | 
 |  | +      for (Long j = 1; j < order-1; j++) {
 | 
											
												
													
														|  | 
 |  | +        //t[0] = t[1] + dt;
 | 
											
												
													
														|  | 
 |  | +        //x[0] = x[1] + grad[1] * dt;
 | 
											
												
													
														|  | 
 |  | +        //g[0] = grad_fn(x[0], grad[0], &grad_op[0]);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        //Real dot_prod = compute_inner_prod(grad[0], grad[1]) / sqrt<Real>(compute_inner_prod(grad[0], grad[0])*compute_inner_prod(grad[1], grad[1]));
 | 
											
												
													
														|  | 
 |  | +        //Real dt_scale = 0.1 / sqrt<Real>(1-dot_prod*dot_prod);
 | 
											
												
													
														|  | 
 |  | +        //dt *= dt_scale;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        //if (dt_scale < 0.5 || g[0] >= g[1]) {
 | 
											
												
													
														|  | 
 |  | +        //  j--;
 | 
											
												
													
														|  | 
 |  | +        //  continue;
 | 
											
												
													
														|  | 
 |  | +        //}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        //std::cout<<"iter = "<<j<<"   t = "<<t[0]<<"   g = "<<g[0]<<"   dt = "<<dt<<'\n';
 | 
											
												
													
														|  | 
 |  | +        //for (Long i = order-1; i >= 1; i--) {
 | 
											
												
													
														|  | 
 |  | +        //  x[i] = x[i-1];
 | 
											
												
													
														|  | 
 |  | +        //  grad[i] = grad[i-1];
 | 
											
												
													
														|  | 
 |  | +        //  grad_op[i] = grad_op[i-1];
 | 
											
												
													
														|  | 
 |  | +        //  g[i] = g[i-1];
 | 
											
												
													
														|  | 
 |  | +        //  t[i] = t[i-1];
 | 
											
												
													
														|  | 
 |  | +        //}
 | 
											
												
													
														|  | 
 |  | +      }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      for (Long j = 0; j < max_iter; j++) {
 | 
											
												
													
														|  | 
 |  | +        Eigen::VectorXd x_, grad_, grad_op_;
 | 
											
												
													
														|  | 
 |  | +        Real g_ = grad_fn(x[1] + grad[1]*(dt*0.5), grad_, &grad_op_);
 | 
											
												
													
														|  | 
 |  | +        Real dt_scale = compute_dt_scale(grad_, grad[1]);
 | 
											
												
													
														|  | 
 |  | +        dt *= dt_scale;
 | 
											
												
													
														|  | 
 |  | +        if (dt_scale < 0.5 || g[0] >= g[1]) {
 | 
											
												
													
														|  | 
 |  | +          std::cout<<"dt = "<<dt<<'\n';
 | 
											
												
													
														|  | 
 |  | +          j--;
 | 
											
												
													
														|  | 
 |  | +          continue;
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        t[0] = t[1] + dt;
 | 
											
												
													
														|  | 
 |  | +        x[0] = x[1] + grad_*dt;
 | 
											
												
													
														|  | 
 |  | +        g[0] = grad_fn(x[0], grad[0], &grad_op[0]);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        dt_scale = compute_dt_scale(grad[0], grad_);
 | 
											
												
													
														|  | 
 |  | +        dt *= dt_scale;
 | 
											
												
													
														|  | 
 |  | +        if (dt_scale < 0.5 || g[0] >= g[1]) {
 | 
											
												
													
														|  | 
 |  | +          std::cout<<"dt =  "<<dt<<'\n';
 | 
											
												
													
														|  | 
 |  | +          j--;
 | 
											
												
													
														|  | 
 |  | +          continue;
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        std::cout<<"iter = "<<j<<"   t = "<<t[0]<<"   g = "<<g[0]<<"   dt = "<<dt<<'\n';
 | 
											
												
													
														|  | 
 |  | +        for (Long i = order-1; i >= 1; i--) {
 | 
											
												
													
														|  | 
 |  | +          x[i] = x[i-1];
 | 
											
												
													
														|  | 
 |  | +          grad[i] = grad[i-1];
 | 
											
												
													
														|  | 
 |  | +          grad_op[i] = grad_op[i-1];
 | 
											
												
													
														|  | 
 |  | +          g[i] = g[i-1];
 | 
											
												
													
														|  | 
 |  | +          t[i] = t[i-1];
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +      }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      for (Long j = 0; j < max_iter; j++) {
 | 
											
												
													
														|  | 
 |  | +        Eigen::VectorXd x_, grad_, grad_op_;
 | 
											
												
													
														|  | 
 |  | +        Real g_ = grad_fn(x[1] + grad[1]*(dt*0.5), grad_, &grad_op_);
 | 
											
												
													
														|  | 
 |  | +        if (compute_dt_scale(grad_, grad[1])<0.5 ||  g_ > g[1]) {
 | 
											
												
													
														|  | 
 |  | +          dt = dt * compute_dt_scale(grad_, grad[1]);
 | 
											
												
													
														|  | 
 |  | +          std::cout<<"dt = "<<dt<<'\n';
 | 
											
												
													
														|  | 
 |  | +          j--;
 | 
											
												
													
														|  | 
 |  | +          continue;
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        t[0] = t[1] + dt;
 | 
											
												
													
														|  | 
 |  | +        x[0] = x[1] + grad_*dt;
 | 
											
												
													
														|  | 
 |  | +        g[0] = grad_fn(x[0], grad[0], &grad_op[0]);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        Real dt_scale = compute_dt_scale(grad[0], grad[1]); /// todo use grad_ instead of grad[1]
 | 
											
												
													
														|  | 
 |  | +        dt *= dt_scale;
 | 
											
												
													
														|  | 
 |  | +        if (dt_scale < 0.5 || g[0] >= g[1]) {
 | 
											
												
													
														|  | 
 |  | +          std::cout<<"dt =  "<<dt<<'\n';
 | 
											
												
													
														|  | 
 |  | +          j--;
 | 
											
												
													
														|  | 
 |  | +          continue;
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        std::cout<<"iter = "<<j<<"   t = "<<t[0]<<"   g = "<<g[0]<<"   dt = "<<dt<<'\n';
 | 
											
												
													
														|  | 
 |  | +        for (Long i = order-1; i >= 1; i--) {
 | 
											
												
													
														|  | 
 |  | +          x[i] = x[i-1];
 | 
											
												
													
														|  | 
 |  | +          grad[i] = grad[i-1];
 | 
											
												
													
														|  | 
 |  | +          grad_op[i] = grad_op[i-1];
 | 
											
												
													
														|  | 
 |  | +          g[i] = g[i-1];
 | 
											
												
													
														|  | 
 |  | +          t[i] = t[i-1];
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +      }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      //for (Long iter = 0; iter < max_iter; iter++) {
 | 
											
												
													
														|  | 
 |  | +      //  t[0] = t[1] + dt;
 | 
											
												
													
														|  | 
 |  | +      //  x[0] = x[1] + grad[1] * dt;
 | 
											
												
													
														|  | 
 |  | +      //  g[0] = grad_fn(x[0], grad[0], &grad_op[0]);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      //  Real dot_prod = compute_inner_prod(grad[0], grad[1]) / sqrt<Real>(compute_inner_prod(grad[0], grad[0])*compute_inner_prod(grad[1], grad[1]));
 | 
											
												
													
														|  | 
 |  | +      //  if (dot_prod < 0.95 || g[0] < g[1]) {
 | 
											
												
													
														|  | 
 |  | +      //    dt = dt * 1.5;
 | 
											
												
													
														|  | 
 |  | +      //  }
 | 
											
												
													
														|  | 
 |  | +      //  if (dot_prod < 0.85 || g[0] >= g[1]) {
 | 
											
												
													
														|  | 
 |  | +      //    dt = dt * 0.5;
 | 
											
												
													
														|  | 
 |  | +      //    continue;
 | 
											
												
													
														|  | 
 |  | +      //  }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      //  for (Long i = order-2; i >= 0; i--) {
 | 
											
												
													
														|  | 
 |  | +      //    x[i+1] = x[i];
 | 
											
												
													
														|  | 
 |  | +      //    grad[i+1] = grad[i];
 | 
											
												
													
														|  | 
 |  | +      //    grad_op[i+1] = grad_op[i];
 | 
											
												
													
														|  | 
 |  | +      //    g[i+1] = g[i];
 | 
											
												
													
														|  | 
 |  | +      //    t[i+1] = t[i];
 | 
											
												
													
														|  | 
 |  | +      //  }
 | 
											
												
													
														|  | 
 |  | +      //}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      //for (Long iter = 0; iter < max_iter; iter++) {
 | 
											
												
													
														|  | 
 |  | +      //  fx = grad_fn(x, grad, &grad_op);
 | 
											
												
													
														|  | 
 |  | +      //  { // Update dt
 | 
											
												
													
														|  | 
 |  | +      //    Eigen::VectorXd grad_(x.size());
 | 
											
												
													
														|  | 
 |  | +      //    Eigen::VectorXd x1 = x - grad * dt * 0.5;
 | 
											
												
													
														|  | 
 |  | +      //    Eigen::VectorXd x2 = x - grad * dt * 1.0;
 | 
											
												
													
														|  | 
 |  | +      //    Real fx1 = grad_fn(x1, grad_);
 | 
											
												
													
														|  | 
 |  | +      //    Real fx2 = grad_fn(x2, grad_);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      //    { // Calculate optimal step size dt
 | 
											
												
													
														|  | 
 |  | +      //      Real a = 2*fx - 4*fx1 + 2*fx2;
 | 
											
												
													
														|  | 
 |  | +      //      Real b =-3*fx + 4*fx1 -   fx2;
 | 
											
												
													
														|  | 
 |  | +      //      Real c = fx;
 | 
											
												
													
														|  | 
 |  | +      //      Real s = -b/(2*a);
 | 
											
												
													
														|  | 
 |  | +      //      dt *= s;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      //      Real fx_ = a*s*s + b*s + c;
 | 
											
												
													
														|  | 
 |  | +      //      std::cout<<"g = "<<fx_<<' ';
 | 
											
												
													
														|  | 
 |  | +      //      std::cout<<fx<<' ';
 | 
											
												
													
														|  | 
 |  | +      //      std::cout<<fx1<<' ';
 | 
											
												
													
														|  | 
 |  | +      //      std::cout<<fx2<<' ';
 | 
											
												
													
														|  | 
 |  | +      //      std::cout<<dt<<'\n';
 | 
											
												
													
														|  | 
 |  | +      //    }
 | 
											
												
													
														|  | 
 |  | +      //  }
 | 
											
												
													
														|  | 
 |  | +      //  x = x - grad * dt;
 | 
											
												
													
														|  | 
 |  | +      //  if (fx < tol) return iter;
 | 
											
												
													
														|  | 
 |  | +      //}
 | 
											
												
													
														|  | 
 |  | +      //return max_iter;
 | 
											
												
													
														|  | 
 |  | +      return 0;
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  |    public:
 |  |    public:
 | 
											
												
													
														|  |      MHDEquilib(const Stellarator<Real,ORDER>& S, const Vector<Real>& pressure, const Vector<Real>& flux_tor, const Vector<Real>& flux_pol) {
 |  |      MHDEquilib(const Stellarator<Real,ORDER>& S, const Vector<Real>& pressure, const Vector<Real>& flux_tor, const Vector<Real>& flux_pol) {
 | 
											
												
													
														|  |        S_ = S;
 |  |        S_ = S;
 | 
											
												
													
														|  |        pressure_ = pressure;
 |  |        pressure_ = pressure;
 | 
											
												
													
														|  |        flux_tor_ = flux_tor;
 |  |        flux_tor_ = flux_tor;
 | 
											
												
													
														|  |        flux_pol_ = flux_pol;
 |  |        flux_pol_ = flux_pol;
 | 
											
												
													
														|  | -      iter = 0;
 |  | 
 | 
											
												
													
														|  | 
 |  | +      iter = 57;
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      Real operator()(const Eigen::VectorXd& x, Eigen::VectorXd& grad_direction, Eigen::VectorXd* grad_op_ptr = nullptr) {
 |  |      Real operator()(const Eigen::VectorXd& x, Eigen::VectorXd& grad_direction, Eigen::VectorXd* grad_op_ptr = nullptr) {
 | 
											
										
											
												
													
														|  | @@ -6047,29 +6428,30 @@ template <class Real, Integer ORDER=10> class MHDEquilib {
 | 
											
												
													
														|  |        Stellarator<Real,ORDER>::compute_norm_area_elem(S_, normal, area_elem);
 |  |        Stellarator<Real,ORDER>::compute_norm_area_elem(S_, normal, area_elem);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |        Real g;
 |  |        Real g;
 | 
											
												
													
														|  | -      Vector<ElemBasis> dgdnu = Stellarator<Real,ORDER>::compute_gradient(S_, pressure_, flux_tor_, flux_pol_, &g);
 |  | 
 | 
											
												
													
														|  | -      //Vector<ElemBasis> dgdnu = Stellarator<Real,ORDER>::compute_pressure_jump(S_, pressure_, flux_tor_, flux_pol_, &g);
 |  | 
 | 
											
												
													
														|  | 
 |  | +      //Vector<ElemBasis> dgdnu = Stellarator<Real,ORDER>::compute_gradient(S_, pressure_, flux_tor_, flux_pol_, &g);
 | 
											
												
													
														|  | 
 |  | +      Vector<ElemBasis> dgdnu = Stellarator<Real,ORDER>::compute_pressure_jump(S_, pressure_, flux_tor_, flux_pol_, &g);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -      Vector<Real> grad_direction_, grad_op_;
 |  | 
 | 
											
												
													
														|  | 
 |  | +      Vector<Real> grad_direction_, grad_op_, grad_direction_orig_;
 | 
											
												
													
														|  |        { // Set grad_direction_ and filter
 |  |        { // Set grad_direction_ and filter
 | 
											
												
													
														|  |          Vector<ElemBasis> H = compute_H(S_.GetElemList(), normal);
 |  |          Vector<ElemBasis> H = compute_H(S_.GetElemList(), normal);
 | 
											
												
													
														|  |          Vector<Real> H_fourier = cheb2grid(S_, H);
 |  |          Vector<Real> H_fourier = cheb2grid(S_, H);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |          grad_op_.ReInit(x.size());
 |  |          grad_op_.ReInit(x.size());
 | 
											
												
													
														|  |          grad_direction_.ReInit(x.size());
 |  |          grad_direction_.ReInit(x.size());
 | 
											
												
													
														|  | 
 |  | +        grad_direction_orig_.ReInit(x.size());
 | 
											
												
													
														|  |          Vector<Real> dgdnu_fourier = cheb2grid(S_, dgdnu);
 |  |          Vector<Real> dgdnu_fourier = cheb2grid(S_, dgdnu);
 | 
											
												
													
														|  |          for (Long i = 0; i < S_.Nsurf(); i++) { // Init grad_direction_, make it divergence-free, filter
 |  |          for (Long i = 0; i < S_.Nsurf(); i++) { // Init grad_direction_, make it divergence-free, filter
 | 
											
												
													
														|  |            const Long Mt = S_.NTor(i);
 |  |            const Long Mt = S_.NTor(i);
 | 
											
												
													
														|  |            const Long Mp = S_.NPol(i);
 |  |            const Long Mp = S_.NPol(i);
 | 
											
												
													
														|  |            const Long offset = S_.ElemDsp(i);
 |  |            const Long offset = S_.ElemDsp(i);
 | 
											
												
													
														|  | -          const Long Nt = Mt * ORDER * fourier_upsample;
 |  | 
 | 
											
												
													
														|  | -          const Long Np = Mp * ORDER * fourier_upsample;
 |  | 
 | 
											
												
													
														|  | 
 |  | +          const Long Nt = fourier_dim0;
 | 
											
												
													
														|  | 
 |  | +          const Long Np = fourier_dim1;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -          const Vector<Real> dgdnu(Nt*Np, (Iterator<Real>)dgdnu_fourier.begin() + offset * (ORDER*ORDER*fourier_upsample*fourier_upsample), false);
 |  | 
 | 
											
												
													
														|  | -          const Vector<Real> H(Nt*Np, (Iterator<Real>)H_fourier.begin() + offset * (ORDER*ORDER*fourier_upsample*fourier_upsample), false);
 |  | 
 | 
											
												
													
														|  | -          const Vector<Real> X(COORD_DIM*Nt*Np, (Iterator<Real>)X_fourier.begin() + COORD_DIM*offset * (ORDER*ORDER*fourier_upsample*fourier_upsample), false);
 |  | 
 | 
											
												
													
														|  | -          Vector<Real> grad_direction(COORD_DIM*Nt*Np, (Iterator<Real>)grad_direction_.begin() + COORD_DIM*offset * (ORDER*ORDER*fourier_upsample*fourier_upsample), false);
 |  | 
 | 
											
												
													
														|  | -          Vector<Real> grad_op(COORD_DIM*Nt*Np, (Iterator<Real>)grad_op_.begin() + COORD_DIM*offset * (ORDER*ORDER*fourier_upsample*fourier_upsample), false);
 |  | 
 | 
											
												
													
														|  | 
 |  | +          const Vector<Real>    dgdnu(          Nt*Np, (Iterator<Real>)dgdnu_fourier.begin()   +           i * (fourier_dim0*fourier_dim1), false);
 | 
											
												
													
														|  | 
 |  | +          const Vector<Real>        H(          Nt*Np, (Iterator<Real>)H_fourier.begin()       +           i * (fourier_dim0*fourier_dim1), false);
 | 
											
												
													
														|  | 
 |  | +          const Vector<Real>        X(COORD_DIM*Nt*Np, (Iterator<Real>)X_fourier.begin()       + COORD_DIM*i * (fourier_dim0*fourier_dim1), false);
 | 
											
												
													
														|  | 
 |  | +          Vector<Real> grad_direction(COORD_DIM*Nt*Np, (Iterator<Real>)grad_direction_.begin() + COORD_DIM*i * (fourier_dim0*fourier_dim1), false);
 | 
											
												
													
														|  | 
 |  | +          Vector<Real>        grad_op(COORD_DIM*Nt*Np, (Iterator<Real>)grad_op_.begin()        + COORD_DIM*i * (fourier_dim0*fourier_dim1), false);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |            Vector<Real> dX, d2X, normal, area_elem;
 |  |            Vector<Real> dX, d2X, normal, area_elem;
 | 
											
												
													
														|  |            biest::SurfaceOp<Real> Sop(comm, Nt, Np);
 |  |            biest::SurfaceOp<Real> Sop(comm, Nt, Np);
 | 
											
										
											
												
													
														|  | @@ -6085,31 +6467,38 @@ template <class Real, Integer ORDER=10> class MHDEquilib {
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |            if (i < S_.Nsurf() - 1) { // Set grad_direction
 |  |            if (i < S_.Nsurf() - 1) { // Set grad_direction
 | 
											
												
													
														|  |              Vector<Real> F(Nt*Np), GradInvLapF;
 |  |              Vector<Real> F(Nt*Np), GradInvLapF;
 | 
											
												
													
														|  | -            for (Long i = 0; i < Nt*Np; i++) { // Set F <-- 2H * dgdnu
 |  | 
 | 
											
												
													
														|  | -              F[i] = 2*H[i] * dgdnu[i];
 |  | 
 | 
											
												
													
														|  | 
 |  | +            for (Long j = 0; j < Nt*Np; j++) { // Set F <-- 2H * dgdnu
 | 
											
												
													
														|  | 
 |  | +              F[j] = 2*H[j] * dgdnu[j];
 | 
											
												
													
														|  |              }
 |  |              }
 | 
											
												
													
														|  |              Sop.GradInvSurfLap(GradInvLapF, dX, d2X, F, 1e-8, 100, 1.0);
 |  |              Sop.GradInvSurfLap(GradInvLapF, dX, d2X, F, 1e-8, 100, 1.0);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -            for (Long i = 0; i < Nt*Np; i++) { // grad_direction <-- normal * dgdnu - GradInvLapF
 |  | 
 | 
											
												
													
														|  | -              grad_direction[0*Nt*Np+i] = normal[0*Nt*Np+i] * dgdnu[i] - GradInvLapF[0*Nt*Np+i]*0;
 |  | 
 | 
											
												
													
														|  | -              grad_direction[1*Nt*Np+i] = normal[1*Nt*Np+i] * dgdnu[i] - GradInvLapF[1*Nt*Np+i]*0;
 |  | 
 | 
											
												
													
														|  | -              grad_direction[2*Nt*Np+i] = normal[2*Nt*Np+i] * dgdnu[i] - GradInvLapF[2*Nt*Np+i]*0;
 |  | 
 | 
											
												
													
														|  | 
 |  | +            for (Long j = 0; j < Nt*Np; j++) { // grad_direction <-- normal * dgdnu - GradInvLapF
 | 
											
												
													
														|  | 
 |  | +              grad_direction[0*Nt*Np+j] = normal[0*Nt*Np+j] * dgdnu[j] - GradInvLapF[0*Nt*Np+j]*0;
 | 
											
												
													
														|  | 
 |  | +              grad_direction[1*Nt*Np+j] = normal[1*Nt*Np+j] * dgdnu[j] - GradInvLapF[1*Nt*Np+j]*0;
 | 
											
												
													
														|  | 
 |  | +              grad_direction[2*Nt*Np+j] = normal[2*Nt*Np+j] * dgdnu[j] - GradInvLapF[2*Nt*Np+j]*0;
 | 
											
												
													
														|  |              }
 |  |              }
 | 
											
												
													
														|  | -            fourier_filter(grad_direction, Nt, Np, 0.1/fourier_upsample);
 |  | 
 | 
											
												
													
														|  | 
 |  | +            { ////////////////////
 | 
											
												
													
														|  | 
 |  | +              Vector<Real> grad_direction_orig(COORD_DIM*Nt*Np, (Iterator<Real>)grad_direction_orig_.begin() + COORD_DIM*i * (fourier_dim0*fourier_dim1), false);
 | 
											
												
													
														|  | 
 |  | +              grad_direction_orig = grad_direction;
 | 
											
												
													
														|  | 
 |  | +            }
 | 
											
												
													
														|  | 
 |  | +            fourier_filter(grad_direction, Nt, Np, 2);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -            for (Long k = 0; k < 20; k++) { // reparameterize
 |  | 
 | 
											
												
													
														|  | 
 |  | +            for (Long k = 0; k < 50; k++) { // reparameterize
 | 
											
												
													
														|  | 
 |  | +              Real max_resid = 0;
 | 
											
												
													
														|  |                Vector<Real> correction(COORD_DIM*Nt*Np);
 |  |                Vector<Real> correction(COORD_DIM*Nt*Np);
 | 
											
												
													
														|  |                for (Long i = 0; i < Nt*Np; i++) { // Set correction
 |  |                for (Long i = 0; i < Nt*Np; i++) { // Set correction
 | 
											
												
													
														|  |                  Real resid = dgdnu[i];
 |  |                  Real resid = dgdnu[i];
 | 
											
												
													
														|  |                  resid -= normal[0*Nt*Np+i] * grad_direction[0*Nt*Np+i];
 |  |                  resid -= normal[0*Nt*Np+i] * grad_direction[0*Nt*Np+i];
 | 
											
												
													
														|  |                  resid -= normal[1*Nt*Np+i] * grad_direction[1*Nt*Np+i];
 |  |                  resid -= normal[1*Nt*Np+i] * grad_direction[1*Nt*Np+i];
 | 
											
												
													
														|  |                  resid -= normal[2*Nt*Np+i] * grad_direction[2*Nt*Np+i];
 |  |                  resid -= normal[2*Nt*Np+i] * grad_direction[2*Nt*Np+i];
 | 
											
												
													
														|  | 
 |  | +                max_resid = std::max(max_resid, fabs(resid));
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |                  correction[0*Nt*Np+i] = normal[0*Nt*Np+i] * resid;
 |  |                  correction[0*Nt*Np+i] = normal[0*Nt*Np+i] * resid;
 | 
											
												
													
														|  |                  correction[1*Nt*Np+i] = normal[1*Nt*Np+i] * resid;
 |  |                  correction[1*Nt*Np+i] = normal[1*Nt*Np+i] * resid;
 | 
											
												
													
														|  |                  correction[2*Nt*Np+i] = normal[2*Nt*Np+i] * resid;
 |  |                  correction[2*Nt*Np+i] = normal[2*Nt*Np+i] * resid;
 | 
											
												
													
														|  |                }
 |  |                }
 | 
											
												
													
														|  | -              fourier_filter(correction, Nt, Np, 0.1/fourier_upsample);
 |  | 
 | 
											
												
													
														|  | 
 |  | +              std::cout<<max_resid<<' '; //////////////////////////////////
 | 
											
												
													
														|  | 
 |  | +              fourier_filter(correction, Nt, Np, 2);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |                Real alpha = 0;
 |  |                Real alpha = 0;
 | 
											
												
													
														|  |                { // Set alpha <-- (dgdnu - x.n, c.n) / (c.n, c.n)
 |  |                { // Set alpha <-- (dgdnu - x.n, c.n) / (c.n, c.n)
 | 
											
										
											
												
													
														|  | @@ -6137,20 +6526,34 @@ template <class Real, Integer ORDER=10> class MHDEquilib {
 | 
											
												
													
														|  |                }
 |  |                }
 | 
											
												
													
														|  |                grad_direction += correction * alpha;
 |  |                grad_direction += correction * alpha;
 | 
											
												
													
														|  |              }
 |  |              }
 | 
											
												
													
														|  | -            //fourier_print_spectrum(dgdnu, Nt, Np);
 |  | 
 | 
											
												
													
														|  | -            //fourier_print_spectrum(grad_direction, Nt, Np);
 |  | 
 | 
											
												
													
														|  | 
 |  | +            //fourier_print_spectrum("dgdnu", dgdnu, Nt, Np);
 | 
											
												
													
														|  | 
 |  | +            //fourier_print_spectrum("grad_dir", grad_direction, Nt, Np);
 | 
											
												
													
														|  |            } else {
 |  |            } else {
 | 
											
												
													
														|  |              grad_direction = 0;
 |  |              grad_direction = 0;
 | 
											
												
													
														|  |            }
 |  |            }
 | 
											
												
													
														|  |          }
 |  |          }
 | 
											
												
													
														|  |        }
 |  |        }
 | 
											
												
													
														|  | -      SCTL_ASSERT(grad_direction.size() == grad_direction_.Dim());
 |  | 
 | 
											
												
													
														|  | -      for (Long i = 0; i < grad_direction.size(); i++) { // Set grad_direction
 |  | 
 | 
											
												
													
														|  | -        grad_direction(i) = grad_direction_[i];
 |  | 
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      /////////////////////////////////////////////////////////////////////////
 | 
											
												
													
														|  | 
 |  | +      fourier_print_spectrum("X", X_fourier, S_);
 | 
											
												
													
														|  | 
 |  | +      fourier_print_spectrum("normal", cheb2grid(S_,normal), S_);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      fourier_print_spectrum("dgdnu", cheb2grid(S_, dgdnu), S_);
 | 
											
												
													
														|  | 
 |  | +      fourier_print_spectrum("grad_dir", grad_direction_, S_);
 | 
											
												
													
														|  | 
 |  | +      fourier_print_spectrum("grad_dir_orig", grad_direction_orig_, S_);
 | 
											
												
													
														|  | 
 |  | +      /////////////////////////////////////////////////////////////////////////
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      { // Set grad_direction <-- grad_direction_
 | 
											
												
													
														|  | 
 |  | +        if (grad_direction.size() != grad_direction_.Dim()) {
 | 
											
												
													
														|  | 
 |  | +          grad_direction = Eigen::VectorXd(grad_direction_.Dim());
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +        for (Long i = 0; i < grad_direction.size(); i++) {
 | 
											
												
													
														|  | 
 |  | +          grad_direction(i) = grad_direction_[i];
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  |        }
 |  |        }
 | 
											
												
													
														|  |        if (grad_op_ptr) { // Set grad_op_ptr
 |  |        if (grad_op_ptr) { // Set grad_op_ptr
 | 
											
												
													
														|  |          grad_op_ptr[0] = Eigen::VectorXd(grad_op_.Dim());
 |  |          grad_op_ptr[0] = Eigen::VectorXd(grad_op_.Dim());
 | 
											
												
													
														|  | -        for (Long i = 0; i < grad_op_ptr->size(); i++) { // Set grad_direction
 |  | 
 | 
											
												
													
														|  | 
 |  | +        for (Long i = 0; i < grad_op_ptr->size(); i++) {
 | 
											
												
													
														|  |            grad_op_ptr[0](i) = grad_op_[i];
 |  |            grad_op_ptr[0](i) = grad_op_[i];
 | 
											
												
													
														|  |          }
 |  |          }
 | 
											
												
													
														|  |        }
 |  |        }
 | 
											
										
											
												
													
														|  | @@ -6195,14 +6598,14 @@ template <class Real, Integer ORDER=10> class MHDEquilib {
 | 
											
												
													
														|  |          }
 |  |          }
 | 
											
												
													
														|  |          Vector<Real> X_fourier = cheb2grid(mhd_equilib.S_, X);
 |  |          Vector<Real> X_fourier = cheb2grid(mhd_equilib.S_, X);
 | 
											
												
													
														|  |          x.resize(X_fourier.Dim());
 |  |          x.resize(X_fourier.Dim());
 | 
											
												
													
														|  | -        // X_fourier.Read(("X"+std::to_string(0)).c_str()); // Read from file
 |  | 
 | 
											
												
													
														|  | 
 |  | +        X_fourier.Read(("X"+std::to_string(mhd_equilib.iter)+"_").c_str()); // Read from file
 | 
											
												
													
														|  |          for (Long i = 0; i < X_fourier.Dim(); i++) {
 |  |          for (Long i = 0; i < X_fourier.Dim(); i++) {
 | 
											
												
													
														|  |            x(i) = X_fourier[i];
 |  |            x(i) = X_fourier[i];
 | 
											
												
													
														|  |          }
 |  |          }
 | 
											
												
													
														|  |        }
 |  |        }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |        Real fx;
 |  |        Real fx;
 | 
											
												
													
														|  | -      if (1) {
 |  | 
 | 
											
												
													
														|  | 
 |  | +      if (0) {
 | 
											
												
													
														|  |          LBFGSpp::LBFGSParam<Real> param;
 |  |          LBFGSpp::LBFGSParam<Real> param;
 | 
											
												
													
														|  |          param.max_iterations = 200;
 |  |          param.max_iterations = 200;
 | 
											
												
													
														|  |          param.epsilon = 1e-16;
 |  |          param.epsilon = 1e-16;
 | 
											
										
											
												
													
														|  | @@ -6210,7 +6613,8 @@ template <class Real, Integer ORDER=10> class MHDEquilib {
 | 
											
												
													
														|  |          LBFGSpp::LBFGSSolver<Real> solver(param);
 |  |          LBFGSpp::LBFGSSolver<Real> solver(param);
 | 
											
												
													
														|  |          Integer niter = solver.minimize(mhd_equilib, x, fx);
 |  |          Integer niter = solver.minimize(mhd_equilib, x, fx);
 | 
											
												
													
														|  |        } else {
 |  |        } else {
 | 
											
												
													
														|  | -        Integer niter = GradientDescent2_(mhd_equilib, x, fx, 200, 1e-12);
 |  | 
 | 
											
												
													
														|  | 
 |  | +        //Integer niter = GradientDescentNew(mhd_equilib, x, fx, 200, 1e-12);
 | 
											
												
													
														|  | 
 |  | +        Integer niter = GradientDescent(mhd_equilib, x, fx, 200, 1e-12);
 | 
											
												
													
														|  |        }
 |  |        }
 | 
											
												
													
														|  |        { // Set x
 |  |        { // Set x
 | 
											
												
													
														|  |          // TODO
 |  |          // TODO
 | 
											
										
											
												
													
														|  | @@ -6227,10 +6631,10 @@ template <class Real, Integer ORDER=10> class MHDEquilib {
 | 
											
												
													
														|  |        { // Init S, flux_tor, flux_pol, pressure
 |  |        { // Init S, flux_tor, flux_pol, pressure
 | 
											
												
													
														|  |          Vector<Long> NtNp;
 |  |          Vector<Long> NtNp;
 | 
											
												
													
														|  |          for (Long i = 0; i < Nsurf; i++) {
 |  |          for (Long i = 0; i < Nsurf; i++) {
 | 
											
												
													
														|  | -          //NtNp.PushBack(50);
 |  | 
 | 
											
												
													
														|  | -          //NtNp.PushBack(8);
 |  | 
 | 
											
												
													
														|  | -          NtNp.PushBack(30);
 |  | 
 | 
											
												
													
														|  | -          NtNp.PushBack(4);
 |  | 
 | 
											
												
													
														|  | 
 |  | +          NtNp.PushBack(70);
 | 
											
												
													
														|  | 
 |  | +          NtNp.PushBack(14);
 | 
											
												
													
														|  | 
 |  | +          //NtNp.PushBack(30);
 | 
											
												
													
														|  | 
 |  | +          //NtNp.PushBack(4);
 | 
											
												
													
														|  |          }
 |  |          }
 | 
											
												
													
														|  |          S = Stellarator<Real,ORDER>(NtNp);
 |  |          S = Stellarator<Real,ORDER>(NtNp);
 | 
											
												
													
														|  |          flux_tor = 1;
 |  |          flux_tor = 1;
 | 
											
										
											
												
													
														|  | @@ -6249,12 +6653,68 @@ template <class Real, Integer ORDER=10> class MHDEquilib {
 | 
											
												
													
														|  |        ComputeEquilibrium(mhd_equilib);
 |  |        ComputeEquilibrium(mhd_equilib);
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | 
 |  | +    static void test_() {
 | 
											
												
													
														|  | 
 |  | +      Comm comm = Comm::World();
 | 
											
												
													
														|  | 
 |  | +      Profile::Enable(true);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      Long Nsurf = 2;
 | 
											
												
													
														|  | 
 |  | +      Stellarator<Real,ORDER> S;
 | 
											
												
													
														|  | 
 |  | +      Vector<Real> flux_tor(Nsurf), flux_pol(Nsurf), pressure(Nsurf);
 | 
											
												
													
														|  | 
 |  | +      { // Init S, flux_tor, flux_pol, pressure
 | 
											
												
													
														|  | 
 |  | +        Vector<Long> NtNp;
 | 
											
												
													
														|  | 
 |  | +        for (Long i = 0; i < Nsurf; i++) {
 | 
											
												
													
														|  | 
 |  | +          NtNp.PushBack(50);
 | 
											
												
													
														|  | 
 |  | +          NtNp.PushBack(10);
 | 
											
												
													
														|  | 
 |  | +          //NtNp.PushBack(30);
 | 
											
												
													
														|  | 
 |  | +          //NtNp.PushBack(4);
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +        S = Stellarator<Real,ORDER>(NtNp);
 | 
											
												
													
														|  | 
 |  | +        flux_tor = 1;
 | 
											
												
													
														|  | 
 |  | +        flux_pol = 1;
 | 
											
												
													
														|  | 
 |  | +        pressure = 0;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        //flux_tor[0] = 1; //0.791881512;
 | 
											
												
													
														|  | 
 |  | +        //flux_tor[1] = 1;
 | 
											
												
													
														|  | 
 |  | +        //flux_pol[0] = 0;
 | 
											
												
													
														|  | 
 |  | +        //flux_pol[1] = 0;
 | 
											
												
													
														|  | 
 |  | +        //pressure[0] = 0;
 | 
											
												
													
														|  | 
 |  | +        //pressure[1] = 0;
 | 
											
												
													
														|  | 
 |  | +      }
 | 
											
												
													
														|  | 
 |  | +      MHDEquilib mhd_equilib(S, pressure, flux_tor, flux_pol);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      const Long Nelem = mhd_equilib.S_.NElem();
 | 
											
												
													
														|  | 
 |  | +      const Long Nnodes = ElemBasis::Size();
 | 
											
												
													
														|  | 
 |  | +      Eigen::VectorXd x, grad_direction;
 | 
											
												
													
														|  | 
 |  | +      { // Read x
 | 
											
												
													
														|  | 
 |  | +        Vector<ElemBasis> X(Nelem * COORD_DIM);
 | 
											
												
													
														|  | 
 |  | +        for (Long i = 0; i < Nelem; i++) {
 | 
											
												
													
														|  | 
 |  | +          X[i*COORD_DIM+0] = S.Elem(i,0);
 | 
											
												
													
														|  | 
 |  | +          X[i*COORD_DIM+1] = S.Elem(i,1);
 | 
											
												
													
														|  | 
 |  | +          X[i*COORD_DIM+2] = S.Elem(i,2);
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +        Vector<Real> X_fourier = cheb2grid(S, X);
 | 
											
												
													
														|  | 
 |  | +        //X_fourier.Read("X_tmp");
 | 
											
												
													
														|  | 
 |  | +        x.resize(X_fourier.Dim());
 | 
											
												
													
														|  | 
 |  | +        for (Long i = 0; i < X_fourier.Dim(); i++) {
 | 
											
												
													
														|  | 
 |  | +          x(i) = X_fourier[i];
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +      }
 | 
											
												
													
														|  | 
 |  | +      Real g = mhd_equilib(x, grad_direction);
 | 
											
												
													
														|  | 
 |  | +      { // Write grad_direction
 | 
											
												
													
														|  | 
 |  | +        Vector<Real> dXdt(grad_direction.size());
 | 
											
												
													
														|  | 
 |  | +        for (Long i = 0; i < dXdt.Dim(); i++) {
 | 
											
												
													
														|  | 
 |  | +          dXdt[i] = grad_direction(i);
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +        dXdt.Write("dXdt_tmp");
 | 
											
												
													
														|  | 
 |  | +      }
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  |    private:
 |  |    private:
 | 
											
												
													
														|  |      Stellarator<Real,ORDER> S_;
 |  |      Stellarator<Real,ORDER> S_;
 | 
											
												
													
														|  |      Vector<Real> pressure_;
 |  |      Vector<Real> pressure_;
 | 
											
												
													
														|  |      Vector<Real> flux_tor_;
 |  |      Vector<Real> flux_tor_;
 | 
											
												
													
														|  |      Vector<Real> flux_pol_;
 |  |      Vector<Real> flux_pol_;
 | 
											
												
													
														|  | -    Long iter = 0;
 |  | 
 | 
											
												
													
														|  | 
 |  | +    Long iter;
 | 
											
												
													
														|  |  };
 |  |  };
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  
 |  |  
 |