|
@@ -5,6 +5,8 @@
|
|
#include <mutex>
|
|
#include <mutex>
|
|
#include <atomic>
|
|
#include <atomic>
|
|
#include <tuple>
|
|
#include <tuple>
|
|
|
|
+#include <Eigen/Core>
|
|
|
|
+#include <LBFGS.h>
|
|
|
|
|
|
namespace SCTL_NAMESPACE {
|
|
namespace SCTL_NAMESPACE {
|
|
|
|
|
|
@@ -2180,6 +2182,7 @@ template <class Real, Integer ORDER=10> class Stellarator {
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ public:
|
|
static Vector<ElemBasis> compute_dot_prod(const Vector<ElemBasis>& A, const Vector<ElemBasis>& B) {
|
|
static Vector<ElemBasis> compute_dot_prod(const Vector<ElemBasis>& A, const Vector<ElemBasis>& B) {
|
|
const Long Nelem = A.Dim() / COORD_DIM;
|
|
const Long Nelem = A.Dim() / COORD_DIM;
|
|
const Long Nnodes = ElemBasis::Size();
|
|
const Long Nnodes = ElemBasis::Size();
|
|
@@ -2834,7 +2837,6 @@ template <class Real, Integer ORDER=10> class Stellarator {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- public:
|
|
|
|
Stellarator(const Vector<Long>& NtNp = Vector<Long>()) {
|
|
Stellarator(const Vector<Long>& NtNp = Vector<Long>()) {
|
|
NtNp_ = NtNp;
|
|
NtNp_ = NtNp;
|
|
Long Nsurf = NtNp_.Dim() / 2;
|
|
Long Nsurf = NtNp_.Dim() / 2;
|
|
@@ -3703,6 +3705,9 @@ template <class Real, Integer ORDER=10> class Stellarator {
|
|
return compute_g(Svec, pressure);
|
|
return compute_g(Svec, pressure);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
static void test() {
|
|
static void test() {
|
|
constexpr Integer order_singular = 15;
|
|
constexpr Integer order_singular = 15;
|
|
constexpr Integer order_direct = 35;
|
|
constexpr Integer order_direct = 35;
|
|
@@ -3732,153 +3737,164 @@ template <class Real, Integer ORDER=10> class Stellarator {
|
|
}
|
|
}
|
|
|
|
|
|
{ // find equilibrium flux surfaces
|
|
{ // find equilibrium flux surfaces
|
|
- const Long Nnodes = ElemBasis::Size();
|
|
|
|
- const Long Nelem = S.NElem();
|
|
|
|
- const Long Nsurf = S.Nsurf();
|
|
|
|
|
|
+ auto filter = [](const Stellarator<Real,ORDER>& S, Vector<ElemBasis>& f) {
|
|
|
|
+ auto cheb2grid = [] (const Vector<ElemBasis>& X, Long Mt, Long Mp, Long Nt, Long Np) {
|
|
|
|
+ const Long dof = X.Dim() / (Mt * Mp);
|
|
|
|
+ SCTL_ASSERT(X.Dim() == Mt * Mp *dof);
|
|
|
|
|
|
- Long iter = 0;
|
|
|
|
- Real dt = 0.1;
|
|
|
|
- while (1) { // time-step
|
|
|
|
- Vector<ElemBasis> normal, area_elem;
|
|
|
|
- compute_norm_area_elem(S, normal, area_elem);
|
|
|
|
- Vector<ElemBasis> dgdnu = compute_gradient(S, pressure, flux_tor, flux_pol)*(-1);
|
|
|
|
- //Vector<ElemBasis> dgdnu = compute_pressure_jump(S, pressure, flux_tor, flux_pol)*(-1);
|
|
|
|
-
|
|
|
|
- Vector<ElemBasis> dXdt(dgdnu.Dim()*COORD_DIM);
|
|
|
|
- { // Set dXdt
|
|
|
|
- dXdt = 0;
|
|
|
|
- for (Long i = 0; i < S.ElemDsp(Nsurf-1); i++) {
|
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
|
- dXdt[i*COORD_DIM+0][j] = normal[i*COORD_DIM+0][j] * dgdnu[i][j];
|
|
|
|
- dXdt[i*COORD_DIM+1][j] = normal[i*COORD_DIM+1][j] * dgdnu[i][j];
|
|
|
|
- dXdt[i*COORD_DIM+2][j] = normal[i*COORD_DIM+2][j] * dgdnu[i][j];
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- for (Long i = 0; i < S.Nsurf(); i++) { // filter dXdt
|
|
|
|
- const Long Nt0 = S.NTor(i);
|
|
|
|
- const Long Np0 = S.NPol(i);
|
|
|
|
- const Long Nelem = Nt0 * Np0;
|
|
|
|
- const Long offset = S.ElemDsp(i);
|
|
|
|
|
|
+ Vector<Real> Xf(dof*Nt*Np); Xf = 0;
|
|
const Long Nnodes = ElemBasis::Size();
|
|
const Long Nnodes = ElemBasis::Size();
|
|
- const Long INTERP_ORDER = 12;
|
|
|
|
- const Long Nt = Nt0*ORDER/5;
|
|
|
|
- const Long Np = Np0*ORDER/5;
|
|
|
|
- for (Long k = 0; k < COORD_DIM; k++) {
|
|
|
|
- Matrix<Real> M(Nt, Np); M = 0;
|
|
|
|
- const auto& quad_wts = ElemBasis::QuadWts();
|
|
|
|
- const Matrix<Real>& Mnodes = Basis<Real,1,ORDER>::Nodes();
|
|
|
|
- for (Long tt = 0; tt < Nt0; tt++) { // Set M
|
|
|
|
- for (Long pp = 0; pp < Np0; pp++) {
|
|
|
|
- for (Long t = 0; t < ORDER; t++) {
|
|
|
|
- for (Long p = 0; p < ORDER; p++) {
|
|
|
|
- Real theta = (tt + Mnodes[0][t]) / Nt0;
|
|
|
|
- Real phi = (pp + Mnodes[0][p]) / Np0;
|
|
|
|
- Long i = (Long)(theta * Nt);
|
|
|
|
- Long j = (Long)(phi * Np);
|
|
|
|
- Real x = theta * Nt - i;
|
|
|
|
- Real y = phi * Np - j;
|
|
|
|
-
|
|
|
|
- Long elem_idx = tt * Np0 + pp;
|
|
|
|
- Long node_idx = p * ORDER + t;
|
|
|
|
-
|
|
|
|
- Vector<Real> Interp0(INTERP_ORDER);
|
|
|
|
- Vector<Real> Interp1(INTERP_ORDER);
|
|
|
|
- { // Set Interp0, Interp1
|
|
|
|
- auto node = [] (Long i) {
|
|
|
|
- return (Real)i - (INTERP_ORDER-1)/2;
|
|
|
|
- };
|
|
|
|
- for (Long i = 0; i < INTERP_ORDER; i++) {
|
|
|
|
- Real wt_x = 1, wt_y = 1;
|
|
|
|
- for (Long j = 0; j < INTERP_ORDER; j++) {
|
|
|
|
- if (j != i) {
|
|
|
|
- wt_x *= (x - node(j)) / (node(i) - node(j));
|
|
|
|
- wt_y *= (y - node(j)) / (node(i) - node(j));
|
|
|
|
- }
|
|
|
|
- Interp0[i] = wt_x;
|
|
|
|
- Interp1[i] = wt_y;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ const Matrix<Real>& Mnodes = Basis<Real,1,ORDER>::Nodes();
|
|
|
|
+ for (Long t = 0; t < Nt; t++) {
|
|
|
|
+ for (Long p = 0; p < Np; p++) {
|
|
|
|
+ Real theta = t / (Real)Nt;
|
|
|
|
+ Real phi = p / (Real)Np;
|
|
|
|
+ Long i = (Long)(theta * Mt);
|
|
|
|
+ Long j = (Long)(phi * Mp);
|
|
|
|
+ Real x = theta * Mt - i;
|
|
|
|
+ Real y = phi * Mp - j;
|
|
|
|
+ Long elem_idx = i * Mp + j;
|
|
|
|
+
|
|
|
|
+ Vector<Real> Interp0(ORDER);
|
|
|
|
+ Vector<Real> Interp1(ORDER);
|
|
|
|
+ { // Set Interp0, Interp1
|
|
|
|
+ auto node = [&Mnodes] (Long i) {
|
|
|
|
+ return Mnodes[0][i];
|
|
|
|
+ };
|
|
|
|
+ for (Long i = 0; i < ORDER; i++) {
|
|
|
|
+ Real wt_x = 1, wt_y = 1;
|
|
|
|
+ for (Long j = 0; j < ORDER; j++) {
|
|
|
|
+ if (j != i) {
|
|
|
|
+ wt_x *= (x - node(j)) / (node(i) - node(j));
|
|
|
|
+ wt_y *= (y - node(j)) / (node(i) - node(j));
|
|
}
|
|
}
|
|
|
|
+ Interp0[i] = wt_x;
|
|
|
|
+ Interp1[i] = wt_y;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
- for (Long ii = 0; ii < INTERP_ORDER; ii++) {
|
|
|
|
- for (Long jj = 0; jj < INTERP_ORDER; jj++) {
|
|
|
|
- Long idx_i = (i + ii-(INTERP_ORDER-1)/2 + Nt) % Nt;
|
|
|
|
- Long idx_j = (j + jj-(INTERP_ORDER-1)/2 + Np) % Np;
|
|
|
|
- M[idx_i][idx_j] += dXdt[(offset+elem_idx)*COORD_DIM+k][node_idx] * quad_wts[node_idx] * Interp0[ii] * Interp1[jj] / (Nt0 * Np0) * (Nt * Np);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ for (Long ii = 0; ii < ORDER; ii++) {
|
|
|
|
+ for (Long jj = 0; jj < ORDER; jj++) {
|
|
|
|
+ Long node_idx = jj * ORDER + ii;
|
|
|
|
+ for (Long k = 0; k < dof; k++) {
|
|
|
|
+ Xf[(k*Nt+t)*Np+p] += X[elem_idx*dof+k][node_idx] * Interp0[ii] * Interp1[jj];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
- for (Long tt = 0; tt < Nt0; tt++) {
|
|
|
|
- for (Long pp = 0; pp < Np0; pp++) {
|
|
|
|
- for (Long t = 0; t < ORDER; t++) {
|
|
|
|
- for (Long p = 0; p < ORDER; p++) {
|
|
|
|
- Matrix<Real> Mnodes = Basis<Real,1,ORDER>::Nodes();
|
|
|
|
- Real theta = (tt + Mnodes[0][t]) / Nt0;
|
|
|
|
- Real phi = (pp + Mnodes[0][p]) / Np0;
|
|
|
|
- Long i = (Long)(theta * Nt);
|
|
|
|
- Long j = (Long)(phi * Np);
|
|
|
|
- Real x = theta * Nt - i;
|
|
|
|
- Real y = phi * Np - j;
|
|
|
|
-
|
|
|
|
- Vector<Real> Interp0(INTERP_ORDER);
|
|
|
|
- Vector<Real> Interp1(INTERP_ORDER);
|
|
|
|
- { // Set Interp0, Interp1
|
|
|
|
- auto node = [] (Long i) {
|
|
|
|
- return (Real)i - (INTERP_ORDER-1)/2;
|
|
|
|
- };
|
|
|
|
- for (Long i = 0; i < INTERP_ORDER; i++) {
|
|
|
|
- Real wt_x = 1, wt_y = 1;
|
|
|
|
- for (Long j = 0; j < INTERP_ORDER; j++) {
|
|
|
|
- if (j != i) {
|
|
|
|
- wt_x *= (x - node(j)) / (node(i) - node(j));
|
|
|
|
- wt_y *= (y - node(j)) / (node(i) - node(j));
|
|
|
|
- }
|
|
|
|
- Interp0[i] = wt_x;
|
|
|
|
- Interp1[i] = wt_y;
|
|
|
|
|
|
+ }
|
|
|
|
+ return Xf;
|
|
|
|
+ };
|
|
|
|
+ auto grid2cheb = [] (const Vector<Real>& Xf, Long Nt, Long Np, Long Mt, Long Mp) {
|
|
|
|
+ Long dof = Xf.Dim() / (Nt*Np);
|
|
|
|
+ SCTL_ASSERT(Xf.Dim() == dof*Nt*Np);
|
|
|
|
+ Vector<ElemBasis> X(Mt*Mp*dof);
|
|
|
|
+ constexpr Integer INTERP_ORDER = 12;
|
|
|
|
+
|
|
|
|
+ for (Long tt = 0; tt < Mt; tt++) {
|
|
|
|
+ for (Long pp = 0; pp < Mp; pp++) {
|
|
|
|
+ for (Long t = 0; t < ORDER; t++) {
|
|
|
|
+ for (Long p = 0; p < ORDER; p++) {
|
|
|
|
+ Matrix<Real> Mnodes = Basis<Real,1,ORDER>::Nodes();
|
|
|
|
+ Real theta = (tt + Mnodes[0][t]) / Mt;
|
|
|
|
+ Real phi = (pp + Mnodes[0][p]) / Mp;
|
|
|
|
+ Long i = (Long)(theta * Nt);
|
|
|
|
+ Long j = (Long)(phi * Np);
|
|
|
|
+ Real x = theta * Nt - i;
|
|
|
|
+ Real y = phi * Np - j;
|
|
|
|
+
|
|
|
|
+ Vector<Real> Interp0(INTERP_ORDER);
|
|
|
|
+ Vector<Real> Interp1(INTERP_ORDER);
|
|
|
|
+ { // Set Interp0, Interp1
|
|
|
|
+ auto node = [] (Long i) {
|
|
|
|
+ return (Real)i - (INTERP_ORDER-1)/2;
|
|
|
|
+ };
|
|
|
|
+ for (Long i = 0; i < INTERP_ORDER; i++) {
|
|
|
|
+ Real wt_x = 1, wt_y = 1;
|
|
|
|
+ for (Long j = 0; j < INTERP_ORDER; j++) {
|
|
|
|
+ if (j != i) {
|
|
|
|
+ wt_x *= (x - node(j)) / (node(i) - node(j));
|
|
|
|
+ wt_y *= (y - node(j)) / (node(i) - node(j));
|
|
}
|
|
}
|
|
|
|
+ Interp0[i] = wt_x;
|
|
|
|
+ Interp1[i] = wt_y;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
|
|
- Real f0 = 0;
|
|
|
|
|
|
+ for (Long k = 0; k < dof; k++) {
|
|
|
|
+ Real X0 = 0;
|
|
for (Long ii = 0; ii < INTERP_ORDER; ii++) {
|
|
for (Long ii = 0; ii < INTERP_ORDER; ii++) {
|
|
for (Long jj = 0; jj < INTERP_ORDER; jj++) {
|
|
for (Long jj = 0; jj < INTERP_ORDER; jj++) {
|
|
Long idx_i = (i + ii-(INTERP_ORDER-1)/2 + Nt) % Nt;
|
|
Long idx_i = (i + ii-(INTERP_ORDER-1)/2 + Nt) % Nt;
|
|
Long idx_j = (j + jj-(INTERP_ORDER-1)/2 + Np) % Np;
|
|
Long idx_j = (j + jj-(INTERP_ORDER-1)/2 + Np) % Np;
|
|
- f0 += Interp0[ii] * Interp1[jj] * M[idx_i][idx_j];
|
|
|
|
|
|
+ X0 += Interp0[ii] * Interp1[jj] * Xf[(k*Nt+idx_i)*Np+idx_j];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
- Long elem_idx = tt * Np0 + pp;
|
|
|
|
|
|
+ Long elem_idx = tt * Mp + pp;
|
|
Long node_idx = p * ORDER + t;
|
|
Long node_idx = p * ORDER + t;
|
|
- dXdt[(offset+elem_idx)*COORD_DIM+k][node_idx] = f0;
|
|
|
|
|
|
+ X[elem_idx*dof+k][node_idx] = X0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+ return X;
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ Long dof = f.Dim() / S.NElem();
|
|
|
|
+ SCTL_ASSERT(f.Dim() == S.NElem() * dof);
|
|
|
|
+ for (Long i = 0; i < S.Nsurf(); i++) {
|
|
|
|
+ const Long Mt = S.NTor(i);
|
|
|
|
+ const Long Mp = S.NPol(i);
|
|
|
|
+ const Long Nelem = Mt * Mp;
|
|
|
|
+ const Long offset = S.ElemDsp(i);
|
|
|
|
+ const Long Nt = Mt * ORDER / 5;
|
|
|
|
+ const Long Np = Mp * ORDER / 5;
|
|
|
|
+
|
|
|
|
+ Vector<ElemBasis> f_(Nelem*dof, f.begin() + offset*dof, false);
|
|
|
|
+ Vector<Real> f_fourier = cheb2grid(f_, Mt, Mp, Nt, Np);
|
|
|
|
+ f_ = grid2cheb(f_fourier, Nt, Np, Mt, Mp);
|
|
}
|
|
}
|
|
|
|
+ };
|
|
|
|
|
|
- { // Update S, dt
|
|
|
|
|
|
+ Long iter = 0;
|
|
|
|
+ Real dt = 0.1;
|
|
|
|
+ while (1) { // time-step
|
|
|
|
+ Vector<ElemBasis> dgdnu = compute_gradient(S, pressure, flux_tor, flux_pol)*(-1);
|
|
|
|
+ //Vector<ElemBasis> dgdnu = compute_pressure_jump(S, pressure, flux_tor, flux_pol)*(-1);
|
|
|
|
+
|
|
|
|
+ Vector<ElemBasis> dXdt(dgdnu.Dim()*COORD_DIM);
|
|
|
|
+ { // Set dXdt
|
|
|
|
+ dXdt = 0;
|
|
|
|
+ const Long Nnodes = ElemBasis::Size();
|
|
|
|
+ Vector<ElemBasis> normal, area_elem;
|
|
|
|
+ compute_norm_area_elem(S, normal, area_elem);
|
|
|
|
+ for (Long i = 0; i < S.ElemDsp(S.Nsurf()-1); i++) {
|
|
|
|
+ for (Long j = 0; j < Nnodes; j++) {
|
|
|
|
+ dXdt[i*COORD_DIM+0][j] = normal[i*COORD_DIM+0][j] * dgdnu[i][j];
|
|
|
|
+ dXdt[i*COORD_DIM+1][j] = normal[i*COORD_DIM+1][j] * dgdnu[i][j];
|
|
|
|
+ dXdt[i*COORD_DIM+2][j] = normal[i*COORD_DIM+2][j] * dgdnu[i][j];
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ filter(S, dXdt);
|
|
|
|
+ }
|
|
|
|
+ { // Update dt
|
|
|
|
+ const Long Nelem = S.NElem();
|
|
Stellarator<Real,ORDER> S0 = S, S1 = S, S2 = S;
|
|
Stellarator<Real,ORDER> S0 = S, S1 = S, S2 = S;
|
|
for (Long i = 0; i < S.NElem(); i++) {
|
|
for (Long i = 0; i < S.NElem(); i++) {
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
|
- S0.Elem(i, 0)[j] += 0.0 * dt * dXdt[i*COORD_DIM+0][j];
|
|
|
|
- S0.Elem(i, 1)[j] += 0.0 * dt * dXdt[i*COORD_DIM+1][j];
|
|
|
|
- S0.Elem(i, 2)[j] += 0.0 * dt * dXdt[i*COORD_DIM+2][j];
|
|
|
|
|
|
+ S0.Elem(i, 0) += dXdt[i*COORD_DIM+0] * 0.0 * dt;
|
|
|
|
+ S0.Elem(i, 1) += dXdt[i*COORD_DIM+1] * 0.0 * dt;
|
|
|
|
+ S0.Elem(i, 2) += dXdt[i*COORD_DIM+2] * 0.0 * dt;
|
|
|
|
|
|
- S1.Elem(i, 0)[j] += 0.5 * dt * dXdt[i*COORD_DIM+0][j];
|
|
|
|
- S1.Elem(i, 1)[j] += 0.5 * dt * dXdt[i*COORD_DIM+1][j];
|
|
|
|
- S1.Elem(i, 2)[j] += 0.5 * dt * dXdt[i*COORD_DIM+2][j];
|
|
|
|
|
|
+ S1.Elem(i, 0) += dXdt[i*COORD_DIM+0] * 0.5 * dt;
|
|
|
|
+ S1.Elem(i, 1) += dXdt[i*COORD_DIM+1] * 0.5 * dt;
|
|
|
|
+ S1.Elem(i, 2) += dXdt[i*COORD_DIM+2] * 0.5 * dt;
|
|
|
|
|
|
- S2.Elem(i, 0)[j] += 1.0 * dt * dXdt[i*COORD_DIM+0][j];
|
|
|
|
- S2.Elem(i, 1)[j] += 1.0 * dt * dXdt[i*COORD_DIM+1][j];
|
|
|
|
- S2.Elem(i, 2)[j] += 1.0 * dt * dXdt[i*COORD_DIM+2][j];
|
|
|
|
- }
|
|
|
|
|
|
+ S2.Elem(i, 0) += dXdt[i*COORD_DIM+0] * 1.0 * dt;
|
|
|
|
+ S2.Elem(i, 1) += dXdt[i*COORD_DIM+1] * 1.0 * dt;
|
|
|
|
+ S2.Elem(i, 2) += dXdt[i*COORD_DIM+2] * 1.0 * dt;
|
|
}
|
|
}
|
|
Real g0 = compute_g(S0, pressure, flux_tor, flux_pol);
|
|
Real g0 = compute_g(S0, pressure, flux_tor, flux_pol);
|
|
Real g1 = compute_g(S1, pressure, flux_tor, flux_pol);
|
|
Real g1 = compute_g(S1, pressure, flux_tor, flux_pol);
|
|
@@ -3897,30 +3913,42 @@ template <class Real, Integer ORDER=10> class Stellarator {
|
|
std::cout<<g2<<' ';
|
|
std::cout<<g2<<' ';
|
|
std::cout<<dt<<'\n';
|
|
std::cout<<dt<<'\n';
|
|
}
|
|
}
|
|
-
|
|
|
|
- for (Long i = 0; i < S.NElem(); i++) {
|
|
|
|
- for (Long j = 0; j < Nnodes; j++) {
|
|
|
|
- S.Elem(i, 0)[j] += dt * dXdt[i*COORD_DIM+0][j];
|
|
|
|
- S.Elem(i, 1)[j] += dt * dXdt[i*COORD_DIM+1][j];
|
|
|
|
- S.Elem(i, 2)[j] += dt * dXdt[i*COORD_DIM+2][j];
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
}
|
|
}
|
|
- iter++;
|
|
|
|
|
|
|
|
- Vector<ElemBasis> pressure_jump = compute_pressure_jump(S, pressure, flux_tor, flux_pol);
|
|
|
|
{ // Write VTU
|
|
{ // Write VTU
|
|
VTUData vtu;
|
|
VTUData vtu;
|
|
- vtu.AddElems(S.GetElemList(), dgdnu, ORDER);
|
|
|
|
|
|
+ vtu.AddElems(S.GetElemList(), dgdnu*dt, ORDER);
|
|
vtu.WriteVTK("dgdnu"+std::to_string(iter), comm);
|
|
vtu.WriteVTK("dgdnu"+std::to_string(iter), comm);
|
|
}
|
|
}
|
|
{ // Write VTU
|
|
{ // Write VTU
|
|
|
|
+ VTUData vtu;
|
|
|
|
+ vtu.AddElems(S.GetElemList(), dXdt*dt, ORDER);
|
|
|
|
+ vtu.WriteVTK("dXdt"+std::to_string(iter), comm);
|
|
|
|
+ }
|
|
|
|
+ { // Write VTU
|
|
|
|
+ Vector<ElemBasis> pressure_jump = compute_pressure_jump(S, pressure, flux_tor, flux_pol);
|
|
VTUData vtu;
|
|
VTUData vtu;
|
|
vtu.AddElems(S.GetElemList(), pressure_jump, ORDER);
|
|
vtu.AddElems(S.GetElemList(), pressure_jump, ORDER);
|
|
vtu.WriteVTK("pressure_jump"+std::to_string(iter), comm);
|
|
vtu.WriteVTK("pressure_jump"+std::to_string(iter), comm);
|
|
}
|
|
}
|
|
- }
|
|
|
|
|
|
|
|
|
|
+ { // Update S <-- filter(S + dXdt * dt)
|
|
|
|
+ const Long Nelem = S.NElem();
|
|
|
|
+ Vector<ElemBasis> X(Nelem*COORD_DIM);
|
|
|
|
+ for (Long i = 0; i < S.NElem(); i++) {
|
|
|
|
+ X[i*COORD_DIM+0] = S.Elem(i, 0) + dXdt[i*COORD_DIM+0] * dt * 0.5;
|
|
|
|
+ X[i*COORD_DIM+1] = S.Elem(i, 1) + dXdt[i*COORD_DIM+1] * dt * 0.5;
|
|
|
|
+ X[i*COORD_DIM+2] = S.Elem(i, 2) + dXdt[i*COORD_DIM+2] * dt * 0.5;
|
|
|
|
+ }
|
|
|
|
+ filter(S, X);
|
|
|
|
+ for (Long i = 0; i < S.NElem(); i++) {
|
|
|
|
+ S.Elem(i, 0) = X[i*COORD_DIM+0];
|
|
|
|
+ S.Elem(i, 1) = X[i*COORD_DIM+1];
|
|
|
|
+ S.Elem(i, 2) = X[i*COORD_DIM+2];
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ iter++;
|
|
|
|
+ }
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -4801,6 +4829,274 @@ template <class Real, Integer ORDER=10> class Stellarator {
|
|
Vector<Long> elem_dsp;
|
|
Vector<Long> elem_dsp;
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+template <class Real, Integer ORDER=10> class MHDEquilib {
|
|
|
|
+ static constexpr Integer COORD_DIM = 3;
|
|
|
|
+ static constexpr Integer ELEM_DIM = COORD_DIM-1;
|
|
|
|
+ using ElemBasis = Basis<Real, ELEM_DIM, ORDER>;
|
|
|
|
+
|
|
|
|
+ public:
|
|
|
|
+ MHDEquilib(const Stellarator<Real,ORDER>& S, const Vector<Real>& pressure, const Vector<Real>& flux_tor, const Vector<Real>& flux_pol) {
|
|
|
|
+ S_ = S;
|
|
|
|
+ pressure_ = pressure;
|
|
|
|
+ flux_tor_ = flux_tor;
|
|
|
|
+ flux_pol_ = flux_pol;
|
|
|
|
+ iter = 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Real operator()(const Eigen::VectorXd& x, Eigen::VectorXd& grad) {
|
|
|
|
+ const Comm comm = Comm::World();
|
|
|
|
+ const Long Nelem = S_.NElem();
|
|
|
|
+ const Long Nnodes = ElemBasis::Size();
|
|
|
|
+ const Long N = Nelem * COORD_DIM * Nnodes;
|
|
|
|
+ SCTL_ASSERT(x.rows() == N);
|
|
|
|
+
|
|
|
|
+ auto filter = [](const Stellarator<Real,ORDER>& S, Vector<ElemBasis>& f) {
|
|
|
|
+ auto cheb2grid = [] (const Vector<ElemBasis>& X, Long Mt, Long Mp, Long Nt, Long Np) {
|
|
|
|
+ const Long dof = X.Dim() / (Mt * Mp);
|
|
|
|
+ SCTL_ASSERT(X.Dim() == Mt * Mp *dof);
|
|
|
|
+
|
|
|
|
+ Vector<Real> Xf(dof*Nt*Np); Xf = 0;
|
|
|
|
+ const Long Nnodes = ElemBasis::Size();
|
|
|
|
+ const Matrix<Real>& Mnodes = Basis<Real,1,ORDER>::Nodes();
|
|
|
|
+ for (Long t = 0; t < Nt; t++) {
|
|
|
|
+ for (Long p = 0; p < Np; p++) {
|
|
|
|
+ Real theta = t / (Real)Nt;
|
|
|
|
+ Real phi = p / (Real)Np;
|
|
|
|
+ Long i = (Long)(theta * Mt);
|
|
|
|
+ Long j = (Long)(phi * Mp);
|
|
|
|
+ Real x = theta * Mt - i;
|
|
|
|
+ Real y = phi * Mp - j;
|
|
|
|
+ Long elem_idx = i * Mp + j;
|
|
|
|
+
|
|
|
|
+ Vector<Real> Interp0(ORDER);
|
|
|
|
+ Vector<Real> Interp1(ORDER);
|
|
|
|
+ { // Set Interp0, Interp1
|
|
|
|
+ auto node = [&Mnodes] (Long i) {
|
|
|
|
+ return Mnodes[0][i];
|
|
|
|
+ };
|
|
|
|
+ for (Long i = 0; i < ORDER; i++) {
|
|
|
|
+ Real wt_x = 1, wt_y = 1;
|
|
|
|
+ for (Long j = 0; j < ORDER; j++) {
|
|
|
|
+ if (j != i) {
|
|
|
|
+ wt_x *= (x - node(j)) / (node(i) - node(j));
|
|
|
|
+ wt_y *= (y - node(j)) / (node(i) - node(j));
|
|
|
|
+ }
|
|
|
|
+ Interp0[i] = wt_x;
|
|
|
|
+ Interp1[i] = wt_y;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for (Long ii = 0; ii < ORDER; ii++) {
|
|
|
|
+ for (Long jj = 0; jj < ORDER; jj++) {
|
|
|
|
+ Long node_idx = jj * ORDER + ii;
|
|
|
|
+ for (Long k = 0; k < dof; k++) {
|
|
|
|
+ Xf[(k*Nt+t)*Np+p] += X[elem_idx*dof+k][node_idx] * Interp0[ii] * Interp1[jj];
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return Xf;
|
|
|
|
+ };
|
|
|
|
+ auto grid2cheb = [] (const Vector<Real>& Xf, Long Nt, Long Np, Long Mt, Long Mp) {
|
|
|
|
+ Long dof = Xf.Dim() / (Nt*Np);
|
|
|
|
+ SCTL_ASSERT(Xf.Dim() == dof*Nt*Np);
|
|
|
|
+ Vector<ElemBasis> X(Mt*Mp*dof);
|
|
|
|
+ constexpr Integer INTERP_ORDER = 12;
|
|
|
|
+
|
|
|
|
+ for (Long tt = 0; tt < Mt; tt++) {
|
|
|
|
+ for (Long pp = 0; pp < Mp; pp++) {
|
|
|
|
+ for (Long t = 0; t < ORDER; t++) {
|
|
|
|
+ for (Long p = 0; p < ORDER; p++) {
|
|
|
|
+ Matrix<Real> Mnodes = Basis<Real,1,ORDER>::Nodes();
|
|
|
|
+ Real theta = (tt + Mnodes[0][t]) / Mt;
|
|
|
|
+ Real phi = (pp + Mnodes[0][p]) / Mp;
|
|
|
|
+ Long i = (Long)(theta * Nt);
|
|
|
|
+ Long j = (Long)(phi * Np);
|
|
|
|
+ Real x = theta * Nt - i;
|
|
|
|
+ Real y = phi * Np - j;
|
|
|
|
+
|
|
|
|
+ Vector<Real> Interp0(INTERP_ORDER);
|
|
|
|
+ Vector<Real> Interp1(INTERP_ORDER);
|
|
|
|
+ { // Set Interp0, Interp1
|
|
|
|
+ auto node = [] (Long i) {
|
|
|
|
+ return (Real)i - (INTERP_ORDER-1)/2;
|
|
|
|
+ };
|
|
|
|
+ for (Long i = 0; i < INTERP_ORDER; i++) {
|
|
|
|
+ Real wt_x = 1, wt_y = 1;
|
|
|
|
+ for (Long j = 0; j < INTERP_ORDER; j++) {
|
|
|
|
+ if (j != i) {
|
|
|
|
+ wt_x *= (x - node(j)) / (node(i) - node(j));
|
|
|
|
+ wt_y *= (y - node(j)) / (node(i) - node(j));
|
|
|
|
+ }
|
|
|
|
+ Interp0[i] = wt_x;
|
|
|
|
+ Interp1[i] = wt_y;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for (Long k = 0; k < dof; k++) {
|
|
|
|
+ Real X0 = 0;
|
|
|
|
+ for (Long ii = 0; ii < INTERP_ORDER; ii++) {
|
|
|
|
+ for (Long jj = 0; jj < INTERP_ORDER; jj++) {
|
|
|
|
+ Long idx_i = (i + ii-(INTERP_ORDER-1)/2 + Nt) % Nt;
|
|
|
|
+ Long idx_j = (j + jj-(INTERP_ORDER-1)/2 + Np) % Np;
|
|
|
|
+ X0 += Interp0[ii] * Interp1[jj] * Xf[(k*Nt+idx_i)*Np+idx_j];
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ Long elem_idx = tt * Mp + pp;
|
|
|
|
+ Long node_idx = p * ORDER + t;
|
|
|
|
+ X[elem_idx*dof+k][node_idx] = X0;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return X;
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ Long dof = f.Dim() / S.NElem();
|
|
|
|
+ SCTL_ASSERT(f.Dim() == S.NElem() * dof);
|
|
|
|
+ for (Long i = 0; i < S.Nsurf(); i++) {
|
|
|
|
+ const Long Mt = S.NTor(i);
|
|
|
|
+ const Long Mp = S.NPol(i);
|
|
|
|
+ const Long Nelem = Mt * Mp;
|
|
|
|
+ const Long offset = S.ElemDsp(i);
|
|
|
|
+ const Long Nt = Mt * ORDER / 10;
|
|
|
|
+ const Long Np = Mp * ORDER / 10;
|
|
|
|
+
|
|
|
|
+ Vector<ElemBasis> f_(Nelem*dof, f.begin() + offset*dof, false);
|
|
|
|
+ Vector<Real> f_fourier = cheb2grid(f_, Mt, Mp, Nt, Np);
|
|
|
|
+ f_ = grid2cheb(f_fourier, Nt, Np, Mt, Mp);
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ for (Long i = 0; i < Nelem; i++) { // Set S_
|
|
|
|
+ for (Long j = 0; j < Nnodes; j++) {
|
|
|
|
+ S_.Elem(i,0)[j] = x[(i*Nnodes+j)*COORD_DIM+0];
|
|
|
|
+ S_.Elem(i,1)[j] = x[(i*Nnodes+j)*COORD_DIM+1];
|
|
|
|
+ S_.Elem(i,2)[j] = x[(i*Nnodes+j)*COORD_DIM+2];
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ Real g = Stellarator<Real,ORDER>::compute_g(S_, pressure_, flux_tor_, flux_pol_);
|
|
|
|
+ Vector<ElemBasis> dgdnu = Stellarator<Real,ORDER>::compute_gradient(S_, pressure_, flux_tor_, flux_pol_);
|
|
|
|
+ Vector<ElemBasis> dXdt(N);
|
|
|
|
+ { // Set dXdt
|
|
|
|
+ dXdt = 0;
|
|
|
|
+ const Long Nnodes = ElemBasis::Size();
|
|
|
|
+ Vector<ElemBasis> normal, area_elem;
|
|
|
|
+ Stellarator<Real,ORDER>::compute_norm_area_elem(S_, normal, area_elem);
|
|
|
|
+ for (Long i = 0; i < S_.ElemDsp(S_.Nsurf()-1); i++) {
|
|
|
|
+ for (Long j = 0; j < Nnodes; j++) {
|
|
|
|
+ dXdt[i*COORD_DIM+0][j] = normal[i*COORD_DIM+0][j] * dgdnu[i][j];
|
|
|
|
+ dXdt[i*COORD_DIM+1][j] = normal[i*COORD_DIM+1][j] * dgdnu[i][j];
|
|
|
|
+ dXdt[i*COORD_DIM+2][j] = normal[i*COORD_DIM+2][j] * dgdnu[i][j];
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ filter(S_, dXdt);
|
|
|
|
+ }
|
|
|
|
+ for (Long i = 0; i < Nelem; i++) { // Set grad
|
|
|
|
+ for (Long j = 0; j < Nnodes; j++) {
|
|
|
|
+ grad[(i*Nnodes+j)*COORD_DIM+0] = dXdt[i*COORD_DIM+0][j];
|
|
|
|
+ grad[(i*Nnodes+j)*COORD_DIM+1] = dXdt[i*COORD_DIM+1][j];
|
|
|
|
+ grad[(i*Nnodes+j)*COORD_DIM+2] = dXdt[i*COORD_DIM+2][j];
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (1) { // Write VTU
|
|
|
|
+ VTUData vtu;
|
|
|
|
+ vtu.AddElems(S_.GetElemList(), dgdnu, ORDER);
|
|
|
|
+ vtu.WriteVTK("dgdnu"+std::to_string(iter), comm);
|
|
|
|
+ }
|
|
|
|
+ std::cout<<"iter = "<<iter<<" g = "<<g<<'\n';
|
|
|
|
+
|
|
|
|
+ iter++;
|
|
|
|
+ return g;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static void ComputeEquilibrium(MHDEquilib& mhd_equilib) {
|
|
|
|
+ const Long Nelem = mhd_equilib.S_.NElem();
|
|
|
|
+ const Long Nnodes = ElemBasis::Size();
|
|
|
|
+ const Long N = Nelem * COORD_DIM * Nnodes;
|
|
|
|
+
|
|
|
|
+ LBFGSpp::LBFGSParam<Real> param;
|
|
|
|
+ param.epsilon = 1e-6;
|
|
|
|
+ param.max_iterations = 100;
|
|
|
|
+
|
|
|
|
+ // Create solver and function object
|
|
|
|
+ LBFGSpp::LBFGSSolver<Real> solver(param);
|
|
|
|
+
|
|
|
|
+ // Initial guess
|
|
|
|
+ Eigen::VectorXd x = Eigen::VectorXd::Zero(N);
|
|
|
|
+ for (Long i = 0; i < Nelem; i++) { // Set x
|
|
|
|
+ for (Long j = 0; j < Nnodes; j++) {
|
|
|
|
+ x((i*Nnodes+j)*COORD_DIM+0) = mhd_equilib.S_.Elem(i,0)[j];
|
|
|
|
+ x((i*Nnodes+j)*COORD_DIM+1) = mhd_equilib.S_.Elem(i,1)[j];
|
|
|
|
+ x((i*Nnodes+j)*COORD_DIM+2) = mhd_equilib.S_.Elem(i,2)[j];
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Real fx;
|
|
|
|
+ Integer niter = solver.minimize(mhd_equilib, x, fx);
|
|
|
|
+ for (Long i = 0; i < Nelem; i++) { // Set x
|
|
|
|
+ for (Long j = 0; j < Nnodes; j++) {
|
|
|
|
+ mhd_equilib.S_.Elem(i,0)[j] = x((i*Nnodes+j)*COORD_DIM+0);
|
|
|
|
+ mhd_equilib.S_.Elem(i,1)[j] = x((i*Nnodes+j)*COORD_DIM+1);
|
|
|
|
+ mhd_equilib.S_.Elem(i,2)[j] = x((i*Nnodes+j)*COORD_DIM+2);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ std::cout << niter << " iterations" <<'\n';
|
|
|
|
+ std::cout << "f(x) = " << fx <<'\n';
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static void test() {
|
|
|
|
+ constexpr Integer order_singular = 25;
|
|
|
|
+ constexpr Integer order_direct = 35;
|
|
|
|
+ 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;
|
|
|
|
+ NtNp.PushBack(50);
|
|
|
|
+ NtNp.PushBack(8);
|
|
|
|
+ NtNp.PushBack(50);
|
|
|
|
+ NtNp.PushBack(8);
|
|
|
|
+ //for (Long i = 0; i < Nsurf; i++) {
|
|
|
|
+ // 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);
|
|
|
|
+ ComputeEquilibrium(mhd_equilib);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private:
|
|
|
|
+ Stellarator<Real,ORDER> S_;
|
|
|
|
+ Vector<Real> pressure_;
|
|
|
|
+ Vector<Real> flux_tor_;
|
|
|
|
+ Vector<Real> flux_pol_;
|
|
|
|
+ Long iter = 0;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
template <class Real, Integer ORDER=5> class Spheres {
|
|
template <class Real, Integer ORDER=5> class Spheres {
|
|
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;
|