diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e1924ba1e..2bad0fa2d1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -352,9 +352,15 @@ set(BOUT_SOURCES ./src/sys/timer.cxx ./src/sys/type_name.cxx ./src/sys/utils.cxx + ./include/bout/metric_tensor.hxx + ./src/mesh/metric_tensor.cxx + ./include/bout/christoffel_symbols.hxx + ./src/mesh/christoffel_symbols.cxx + ./include/bout/g_values.hxx + ./src/mesh/g_values.cxx ${CMAKE_CURRENT_BINARY_DIR}/include/bout/revision.hxx ${CMAKE_CURRENT_BINARY_DIR}/include/bout/version.hxx - ) +) find_package(Python3) diff --git a/examples/6field-simple/elm_6f.cxx b/examples/6field-simple/elm_6f.cxx index 40e4f7b3b3..a38a1420e2 100644 --- a/examples/6field-simple/elm_6f.cxx +++ b/examples/6field-simple/elm_6f.cxx @@ -361,7 +361,7 @@ class Elm_6f : public PhysicsModel { result.allocate(); for (auto i : result) { result[i] = - (fp[i.yp()] - fm[i.ym()]) / (2. * coord->dy[i] * sqrt(coord->g_22[i])); + (fp[i.yp()] - fm[i.ym()]) / (2. * coord->dy()[i] * sqrt(coord->g_22()[i])); } } else { result = Grad_par(f, loc); @@ -705,7 +705,7 @@ class Elm_6f : public PhysicsModel { if (mesh->IncIntShear) { // BOUT-06 style, using d/dx = d/dpsi + I * d/dz - coord->IntShiftTorsion = I; + coord->setIntShiftTorsion(I); } else { // Dimits style, using local coordinate system @@ -867,7 +867,7 @@ class Elm_6f : public PhysicsModel { Btxy /= Bbar; B0 /= Bbar; hthe /= Lbar; - coord->dx /= Lbar * Lbar * Bbar; + coord->setDx(coord->dx() / (Lbar * Lbar * Bbar)); I *= Lbar * Lbar * Bbar; if ((!T0_fake_prof) && n0_fake_prof) { @@ -1051,24 +1051,25 @@ class Elm_6f : public PhysicsModel { /**************** CALCULATE METRICS ******************/ - coord->g11 = SQ(Rxy * Bpxy); - coord->g22 = 1.0 / SQ(hthe); - coord->g33 = SQ(I) * coord->g11 + SQ(B0) / coord->g11; - coord->g12 = 0.0; - coord->g13 = -I * coord->g11; - coord->g23 = -Btxy / (hthe * Bpxy * Rxy); + const auto g11 = SQ(Rxy * Bpxy); + const auto g22 = 1.0 / SQ(hthe); + const auto g33 = SQ(I) * g11 + SQ(B0) / g11; + const auto g12 = 0.0; + const auto g13 = -I * g11; + const auto g23 = -Btxy / (hthe * Bpxy * Rxy); - coord->J = hthe / Bpxy; - coord->Bxy = B0; + const auto g_11 = 1.0 / g11 + SQ(I * Rxy); + const auto g_22 = SQ(B0 * hthe / Bpxy); + const auto g_33 = Rxy * Rxy; + const auto g_12 = Btxy * hthe * I * Rxy / Bpxy; + const auto g_13 = I * Rxy * Rxy; + const auto g_23 = Btxy * hthe * Rxy / Bpxy; - coord->g_11 = 1.0 / coord->g11 + SQ(I * Rxy); - coord->g_22 = SQ(B0 * hthe / Bpxy); - coord->g_33 = Rxy * Rxy; - coord->g_12 = Btxy * hthe * I * Rxy / Bpxy; - coord->g_13 = I * Rxy * Rxy; - coord->g_23 = Btxy * hthe * Rxy / Bpxy; + coord->setMetricTensor(ContravariantMetricTensor(g11, g22, g33, g12, g13, g23), + CovariantMetricTensor(g_11, g_22, g_33, g_12, g_13, g_23)); - coord->geometry(); // Calculate quantities from metric tensor + coord->setJ(hthe / Bpxy); + coord->setBxy(B0); // Set B field vector @@ -1446,11 +1447,11 @@ class Elm_6f : public PhysicsModel { if (hyperviscos > 0.0) { // Calculate coefficient. - hyper_mu_x = hyperviscos * coord->g_11 * SQ(coord->dx) - * abs(coord->g11 * D2DX2(U)) / (abs(U) + 1e-3); + hyper_mu_x = hyperviscos * coord->g_11() * SQ(coord->dx()) + * abs(coord->g11() * D2DX2(U)) / (abs(U) + 1e-3); hyper_mu_x.applyBoundary("dirichlet"); // Set to zero on all boundaries - ddt(U) += hyper_mu_x * coord->g11 * D2DX2(U); + ddt(U) += hyper_mu_x * coord->g11() * D2DX2(U); if (first_run) { // Print out maximum values of viscosity used on this processor diff --git a/examples/IMEX/drift-wave-constraint/test-drift.cxx b/examples/IMEX/drift-wave-constraint/test-drift.cxx index e3bf88acfc..c5a16f3706 100644 --- a/examples/IMEX/drift-wave-constraint/test-drift.cxx +++ b/examples/IMEX/drift-wave-constraint/test-drift.cxx @@ -82,7 +82,7 @@ class DriftWave : public PhysicsModel { // ddt(phi) = Delp2(phi) - Vort; // This version uses central differencing for Delp2 - ddt(phi) = (coord->g11 * D2DX2(phi) + coord->g33 * D2DZ2(phi)) - Vort; + ddt(phi) = (coord->g11() * D2DX2(phi) + coord->g33() * D2DZ2(phi)) - Vort; return 0; } diff --git a/examples/conducting-wall-mode/cwm.cxx b/examples/conducting-wall-mode/cwm.cxx index 6ad23033ee..6442e37857 100644 --- a/examples/conducting-wall-mode/cwm.cxx +++ b/examples/conducting-wall-mode/cwm.cxx @@ -65,7 +65,7 @@ class CWM : public PhysicsModel { // Load metrics GRID_LOAD(Rxy, Zxy, Bpxy, Btxy, hthe); - mesh->get(coord->dx, "dpsi"); + coord->setDx(mesh->get("dpsi")); mesh->get(I, "sinty"); // Load normalisation values @@ -136,35 +136,36 @@ class CWM : public PhysicsModel { Rxy /= rho_s; hthe /= rho_s; I *= rho_s * rho_s * (bmag / 1e4) * ShearFactor; - coord->dx /= rho_s * rho_s * (bmag / 1e4); + coord->setDx(coord->dx() / (rho_s * rho_s * (bmag / 1e4))); // Normalise magnetic field Bpxy /= (bmag / 1.e4); Btxy /= (bmag / 1.e4); - coord->Bxy /= (bmag / 1.e4); + coord->setBxy(coord->Bxy() / (bmag / 1.e4)); // Set nu nu = nu_hat * Ni0 / pow(Te0, 1.5); /**************** CALCULATE METRICS ******************/ - coord->g11 = SQ(Rxy * Bpxy); - coord->g22 = 1.0 / SQ(hthe); - coord->g33 = SQ(I) * coord->g11 + SQ(coord->Bxy) / coord->g11; - coord->g12 = 0.0; - coord->g13 = -I * coord->g11; - coord->g23 = -Btxy / (hthe * Bpxy * Rxy); + const auto g11 = SQ(Rxy * Bpxy); + const auto g22 = 1.0 / SQ(hthe); + const auto g33 = SQ(I) * g11 + SQ(coord->Bxy()) / g11; + const auto g12 = 0.0; + const auto g13 = -I * g11; + const auto g23 = -Btxy / (hthe * Bpxy * Rxy); - coord->J = hthe / Bpxy; + const auto g_11 = 1.0 / g11 + SQ(I * Rxy); + const auto g_22 = SQ(coord->Bxy() * hthe / Bpxy); + const auto g_33 = Rxy * Rxy; + const auto g_12 = Btxy * hthe * I * Rxy / Bpxy; + const auto g_13 = I * Rxy * Rxy; + const auto g_23 = Btxy * hthe * Rxy / Bpxy; - coord->g_11 = 1.0 / coord->g11 + SQ(I * Rxy); - coord->g_22 = SQ(coord->Bxy * hthe / Bpxy); - coord->g_33 = Rxy * Rxy; - coord->g_12 = Btxy * hthe * I * Rxy / Bpxy; - coord->g_13 = I * Rxy * Rxy; - coord->g_23 = Btxy * hthe * Rxy / Bpxy; + coord->setMetricTensor(ContravariantMetricTensor(g11, g22, g33, g12, g13, g23), + CovariantMetricTensor(g_11, g_22, g_33, g_12, g_13, g_23)); - coord->geometry(); + coord->setJ(hthe / Bpxy); /**************** SET EVOLVING VARIABLES *************/ @@ -349,7 +350,7 @@ class CWM : public PhysicsModel { result = VDDX(DDZ(p), f); } else { // Use full expression with all terms - result = b0xGrad_dot_Grad(p, f) / coord->Bxy; + result = b0xGrad_dot_Grad(p, f) / coord->Bxy(); } return result; } @@ -361,7 +362,7 @@ class CWM : public PhysicsModel { result = VDDZ(-DDX(p), f); } else { // Use full expression with all terms - result = b0xGrad_dot_Grad(p, f) / coord->Bxy; + result = b0xGrad_dot_Grad(p, f) / coord->Bxy(); } return result; } @@ -373,7 +374,7 @@ class CWM : public PhysicsModel { result = VDDX(DDZ(p), f) + VDDZ(-DDX(p), f); } else { // Use full expression with all terms - result = b0xGrad_dot_Grad(p, f) / coord->Bxy; + result = b0xGrad_dot_Grad(p, f) / coord->Bxy(); } return result; } diff --git a/examples/constraints/alfven-wave/alfven.cxx b/examples/constraints/alfven-wave/alfven.cxx index 3e643331a1..2c12c9a568 100644 --- a/examples/constraints/alfven-wave/alfven.cxx +++ b/examples/constraints/alfven-wave/alfven.cxx @@ -170,7 +170,7 @@ class Alfven : public PhysicsModel { Field2D dx; if (!mesh->get(dx, "dpsi")) { output << "\tUsing dpsi as the x grid spacing\n"; - coord->dx = dx; // Only use dpsi if found + coord->setDx(dx); // Only use dpsi if found } else { // dx will have been read already from the grid output << "\tUsing dx as the x grid spacing\n"; @@ -179,11 +179,11 @@ class Alfven : public PhysicsModel { Rxy /= Lnorm; hthe /= Lnorm; sinty *= SQ(Lnorm) * Bnorm; - coord->dx /= SQ(Lnorm) * Bnorm; + coord->setDx(coord->dx() / (SQ(Lnorm) * Bnorm)); Bpxy /= Bnorm; Btxy /= Bnorm; - coord->Bxy /= Bnorm; + coord->setBxy(coord->Bxy() / Bnorm); // Check type of parallel transform std::string ptstr = @@ -201,23 +201,24 @@ class Alfven : public PhysicsModel { // Calculate metric components - coord->g11 = SQ(Rxy * Bpxy); - coord->g22 = 1.0 / SQ(hthe); - coord->g33 = SQ(sinty) * coord->g11 + SQ(coord->Bxy) / coord->g11; - coord->g12 = 0.0; - coord->g13 = -sinty * coord->g11; - coord->g23 = -sbp * Btxy / (hthe * Bpxy * Rxy); + const auto g11 = SQ(Rxy * Bpxy); + const auto g22 = 1.0 / SQ(hthe); + const auto g33 = SQ(sinty) * g11 + SQ(coord->Bxy()) / g11; + const auto g12 = 0.0; + const auto g13 = -sinty * g11; + const auto g23 = -sbp * Btxy / (hthe * Bpxy * Rxy); - coord->J = hthe / Bpxy; + const auto g_11 = 1.0 / g11 + SQ(sinty * Rxy); + const auto g_22 = SQ(coord->Bxy() * hthe / Bpxy); + const auto g_33 = Rxy * Rxy; + const auto g_12 = sbp * Btxy * hthe * sinty * Rxy / Bpxy; + const auto g_13 = sinty * Rxy * Rxy; + const auto g_23 = sbp * Btxy * hthe * Rxy / Bpxy; - coord->g_11 = 1.0 / coord->g11 + SQ(sinty * Rxy); - coord->g_22 = SQ(coord->Bxy * hthe / Bpxy); - coord->g_33 = Rxy * Rxy; - coord->g_12 = sbp * Btxy * hthe * sinty * Rxy / Bpxy; - coord->g_13 = sinty * Rxy * Rxy; - coord->g_23 = sbp * Btxy * hthe * Rxy / Bpxy; + coord->setMetricTensor(ContravariantMetricTensor(g11, g22, g33, g12, g13, g23), + CovariantMetricTensor(g_11, g_22, g_33, g_12, g_13, g_23)); - coord->geometry(); + coord->setJ(hthe / Bpxy); } }; diff --git a/examples/dalf3/dalf3.cxx b/examples/dalf3/dalf3.cxx index 493e8f5e45..7f73ed56d7 100644 --- a/examples/dalf3/dalf3.cxx +++ b/examples/dalf3/dalf3.cxx @@ -243,29 +243,30 @@ class DALF3 : public PhysicsModel { Btxy /= Bnorm; B0 /= Bnorm; - coord->dx /= rho_s * rho_s * Bnorm; + coord->setDx(coord->dx() / (rho_s * rho_s * Bnorm)); /////////////////////////////////////////////////// // CALCULATE METRICS - coord->g11 = SQ(Rxy * Bpxy); - coord->g22 = 1.0 / SQ(hthe); - coord->g33 = SQ(I) * coord->g11 + SQ(B0) / coord->g11; - coord->g12 = 0.0; - coord->g13 = -I * coord->g11; - coord->g23 = -Btxy / (hthe * Bpxy * Rxy); - - coord->J = hthe / Bpxy; - coord->Bxy = B0; - - coord->g_11 = 1.0 / coord->g11 + SQ(I * Rxy); - coord->g_22 = SQ(B0 * hthe / Bpxy); - coord->g_33 = Rxy * Rxy; - coord->g_12 = Btxy * hthe * I * Rxy / Bpxy; - coord->g_13 = I * Rxy * Rxy; - coord->g_23 = Btxy * hthe * Rxy / Bpxy; - - coord->geometry(); // Calculate quantities from metric tensor + const auto g11 = SQ(Rxy * Bpxy); + const auto g22 = 1.0 / SQ(hthe); + const auto g33 = SQ(I) * g11 + SQ(B0) / g11; + const auto g12 = 0.0; + const auto g13 = -I * g11; + const auto g23 = -Btxy / (hthe * Bpxy * Rxy); + + const auto g_11 = 1.0 / g11 + SQ(I * Rxy); + const auto g_22 = SQ(B0 * hthe / Bpxy); + const auto g_33 = Rxy * Rxy; + const auto g_12 = Btxy * hthe * I * Rxy / Bpxy; + const auto g_13 = I * Rxy * Rxy; + const auto g_23 = Btxy * hthe * Rxy / Bpxy; + + coord->setMetricTensor(ContravariantMetricTensor(g11, g22, g33, g12, g13, g23), + CovariantMetricTensor(g_11, g_22, g_33, g_12, g_13, g_23)); + + coord->setJ(hthe / Bpxy); + coord->setBxy(B0); SOLVE_FOR3(Vort, Pe, Vpar); comms.add(Vort, Pe, Vpar); diff --git a/examples/elm-pb-outerloop/elm_pb_outerloop.cxx b/examples/elm-pb-outerloop/elm_pb_outerloop.cxx index 8e84901806..747d1f8f6e 100644 --- a/examples/elm-pb-outerloop/elm_pb_outerloop.cxx +++ b/examples/elm-pb-outerloop/elm_pb_outerloop.cxx @@ -825,7 +825,7 @@ class ELMpb : public PhysicsModel { if (mesh->IncIntShear) { // BOUT-06 style, using d/dx = d/dpsi + I * d/dz - metric->IntShiftTorsion = I; + metric->setIntShiftTorsion(I); } else { // Dimits style, using local coordinate system @@ -962,7 +962,7 @@ class ELMpb : public PhysicsModel { Btxy /= Bbar; B0 /= Bbar; hthe /= Lbar; - metric->dx /= Lbar * Lbar * Bbar; + metric->setDx(metric->dx() / (Lbar * Lbar * Bbar)); I *= Lbar * Lbar * Bbar; if (constn0) { @@ -1092,24 +1092,25 @@ class ELMpb : public PhysicsModel { /**************** CALCULATE METRICS ******************/ - metric->g11 = SQ(Rxy * Bpxy); - metric->g22 = 1.0 / SQ(hthe); - metric->g33 = SQ(I) * metric->g11 + SQ(B0) / metric->g11; - metric->g12 = 0.0; - metric->g13 = -I * metric->g11; - metric->g23 = -Btxy / (hthe * Bpxy * Rxy); + const auto g11 = SQ(Rxy * Bpxy); + const auto g22 = 1.0 / SQ(hthe); + const auto g33 = SQ(I) * g11 + SQ(B0) / g11; + const auto g12 = 0.0; + const auto g13 = -I * g11; + const auto g23 = -Btxy / (hthe * Bpxy * Rxy); - metric->J = hthe / Bpxy; - metric->Bxy = B0; + const auto g_11 = 1.0 / g11 + SQ(I * Rxy); + const auto g_22 = SQ(B0 * hthe / Bpxy); + const auto g_33 = Rxy * Rxy; + const auto g_12 = Btxy * hthe * I * Rxy / Bpxy; + const auto g_13 = I * Rxy * Rxy; + const auto g_23 = Btxy * hthe * Rxy / Bpxy; - metric->g_11 = 1.0 / metric->g11 + SQ(I * Rxy); - metric->g_22 = SQ(B0 * hthe / Bpxy); - metric->g_33 = Rxy * Rxy; - metric->g_12 = Btxy * hthe * I * Rxy / Bpxy; - metric->g_13 = I * Rxy * Rxy; - metric->g_23 = Btxy * hthe * Rxy / Bpxy; + metric->setMetricTensor(ContravariantMetricTensor(g11, g22, g33, g12, g13, g23), + CovariantMetricTensor(g_11, g_22, g_33, g_12, g_13, g_23)); - metric->geometry(); // Calculate quantities from metric tensor + metric->setJ(hthe / Bpxy); + metric->setBxy(B0); // Set B field vector @@ -1792,11 +1793,11 @@ class ELMpb : public PhysicsModel { if (hyperviscos > 0.0) { // Calculate coefficient. - hyper_mu_x = hyperviscos * metric->g_11 * SQ(metric->dx) - * abs(metric->g11 * D2DX2(U)) / (abs(U) + 1e-3); + hyper_mu_x = hyperviscos * metric->g_11() * SQ(metric->dx()) + * abs(metric->g11() * D2DX2(U)) / (abs(U) + 1e-3); hyper_mu_x.applyBoundary("dirichlet"); // Set to zero on all boundaries - ddt(U) += hyper_mu_x * metric->g11 * D2DX2(U); + ddt(U) += hyper_mu_x * metric->g11() * D2DX2(U); if (first_run) { // Print out maximum values of viscosity used on this processor output.write(" Hyper-viscosity values:\n"); @@ -1907,7 +1908,7 @@ class ELMpb : public PhysicsModel { BoutReal pnorm = P0(0, 0); ddt(P) += heating_P * source_expx2(P0, 2. * hp_width, 0.5 * hp_length) * (Tbar / pnorm); // heat source - ddt(P) += (100. * source_tanhx(P0, hp_width, hp_length) + 0.01) * metric->g11 + ddt(P) += (100. * source_tanhx(P0, hp_width, hp_length) + 0.01) * metric->g11() * D2DX2(P) * (Tbar / Lbar / Lbar); // radial diffusion } diff --git a/examples/elm-pb/elm_pb.cxx b/examples/elm-pb/elm_pb.cxx index f108e58e2f..675970b3a8 100644 --- a/examples/elm-pb/elm_pb.cxx +++ b/examples/elm-pb/elm_pb.cxx @@ -766,7 +766,7 @@ class ELMpb : public PhysicsModel { if (mesh->IncIntShear) { // BOUT-06 style, using d/dx = d/dpsi + I * d/dz - metric->IntShiftTorsion = I; + metric->setIntShiftTorsion(I); } else { // Dimits style, using local coordinate system @@ -903,7 +903,7 @@ class ELMpb : public PhysicsModel { Btxy /= Bbar; B0 /= Bbar; hthe /= Lbar; - metric->dx /= Lbar * Lbar * Bbar; + metric->setDx(metric->dx() / (Lbar * Lbar * Bbar)); I *= Lbar * Lbar * Bbar; if (constn0) { @@ -1033,24 +1033,25 @@ class ELMpb : public PhysicsModel { /**************** CALCULATE METRICS ******************/ - metric->g11 = SQ(Rxy * Bpxy); - metric->g22 = 1.0 / SQ(hthe); - metric->g33 = SQ(I) * metric->g11 + SQ(B0) / metric->g11; - metric->g12 = 0.0; - metric->g13 = -I * metric->g11; - metric->g23 = -Btxy / (hthe * Bpxy * Rxy); + const auto g11 = SQ(Rxy * Bpxy); + const auto g22 = 1.0 / SQ(hthe); + const auto g33 = SQ(I) * g11 + SQ(B0) / g11; + const auto g12 = 0.0; + const auto g13 = -I * g11; + const auto g23 = -Btxy / (hthe * Bpxy * Rxy); - metric->J = hthe / Bpxy; - metric->Bxy = B0; + const auto g_11 = 1.0 / g11 + SQ(I * Rxy); + const auto g_22 = SQ(B0 * hthe / Bpxy); + const auto g_33 = Rxy * Rxy; + const auto g_12 = Btxy * hthe * I * Rxy / Bpxy; + const auto g_13 = I * Rxy * Rxy; + const auto g_23 = Btxy * hthe * Rxy / Bpxy; - metric->g_11 = 1.0 / metric->g11 + SQ(I * Rxy); - metric->g_22 = SQ(B0 * hthe / Bpxy); - metric->g_33 = Rxy * Rxy; - metric->g_12 = Btxy * hthe * I * Rxy / Bpxy; - metric->g_13 = I * Rxy * Rxy; - metric->g_23 = Btxy * hthe * Rxy / Bpxy; + metric->setMetricTensor(ContravariantMetricTensor(g11, g22, g33, g12, g13, g23), + CovariantMetricTensor(g_11, g_22, g_33, g_12, g_13, g_23)); - metric->geometry(); // Calculate quantities from metric tensor + metric->setJ(hthe / Bpxy); + metric->setBxy(B0); // Set B field vector @@ -1603,11 +1604,11 @@ class ELMpb : public PhysicsModel { if (hyperviscos > 0.0) { // Calculate coefficient. - hyper_mu_x = hyperviscos * metric->g_11 * SQ(metric->dx) - * abs(metric->g11 * D2DX2(U)) / (abs(U) + 1e-3); + hyper_mu_x = hyperviscos * metric->g_11() * SQ(metric->dx()) + * abs(metric->g11() * D2DX2(U)) / (abs(U) + 1e-3); hyper_mu_x.applyBoundary("dirichlet"); // Set to zero on all boundaries - ddt(U) += hyper_mu_x * metric->g11 * D2DX2(U); + ddt(U) += hyper_mu_x * metric->g11() * D2DX2(U); if (first_run) { // Print out maximum values of viscosity used on this processor output.write(" Hyper-viscosity values:\n"); @@ -1718,7 +1719,7 @@ class ELMpb : public PhysicsModel { BoutReal pnorm = P0(0, 0); ddt(P) += heating_P * source_expx2(P0, 2. * hp_width, 0.5 * hp_length) * (Tbar / pnorm); // heat source - ddt(P) += (100. * source_tanhx(P0, hp_width, hp_length) + 0.01) * metric->g11 + ddt(P) += (100. * source_tanhx(P0, hp_width, hp_length) + 0.01) * metric->g11() * D2DX2(P) * (Tbar / Lbar / Lbar); // radial diffusion } diff --git a/examples/fci-wave/fci-wave.cxx b/examples/fci-wave/fci-wave.cxx index 9f8bb18b8f..0ea61f3e8d 100644 --- a/examples/fci-wave/fci-wave.cxx +++ b/examples/fci-wave/fci-wave.cxx @@ -45,7 +45,7 @@ class FCIwave : public PhysicsModel { for (auto i : result.getRegion(RGN_NOBNDRY)) { result[i] = Bxyz[i] * (f_B.yup()[i.yp()] - f_B.ydown()[i.ym()]) - / (2. * coord->dy[i] * sqrt(coord->g_22[i])); + / (2. * coord->dy()[i] * sqrt(coord->g_22()[i])); if (!finite(result[i])) { output.write("[{:d},{:d},{:d}]: {:e}, {:e} -> {:e}\n", i.x(), i.y(), i.z(), diff --git a/examples/gyro-gem/gem.cxx b/examples/gyro-gem/gem.cxx index 1a056c1c08..cad585beb4 100644 --- a/examples/gyro-gem/gem.cxx +++ b/examples/gyro-gem/gem.cxx @@ -365,28 +365,29 @@ class GEM : public PhysicsModel { Bxy /= Bbar; Rxy /= rho_s; // Perpendicular derivatives normalised to rho_s - coord->dx /= rho_s * rho_s * Bbar; + coord->setDx(coord->dx() / (rho_s * rho_s * Bbar)); // Metric components - coord->g11 = SQ(Rxy * Bpxy); - coord->g22 = 1.0 / SQ(hthe); - coord->g33 = SQ(Bxy) / coord->g11; - coord->g12 = 0.0; - coord->g13 = 0.; - coord->g23 = -Btxy / (hthe * Bpxy * Rxy); + const auto g11 = SQ(Rxy * Bpxy); + const auto g22 = 1.0 / SQ(hthe); + const auto g33 = SQ(Bxy) / g11; + const auto g12 = 0.0; + const auto g13 = 0.; + const auto g23 = -Btxy / (hthe * Bpxy * Rxy); - coord->J = hthe / Bpxy; - coord->Bxy = Bxy; + const auto g_11 = 1.0 / g11; + const auto g_22 = SQ(Bxy * hthe / Bpxy); + const auto g_33 = Rxy * Rxy; + const auto g_12 = 0.; + const auto g_13 = 0.; + const auto g_23 = Btxy * hthe * Rxy / Bpxy; - coord->g_11 = 1.0 / coord->g11; - coord->g_22 = SQ(Bxy * hthe / Bpxy); - coord->g_33 = Rxy * Rxy; - coord->g_12 = 0.; - coord->g_13 = 0.; - coord->g_23 = Btxy * hthe * Rxy / Bpxy; + coord->setMetricTensor(ContravariantMetricTensor(g11, g22, g33, g12, g13, g23), + CovariantMetricTensor(g_11, g_22, g_33, g_12, g_13, g_23)); - coord->geometry(); + coord->setJ(hthe / Bpxy); + coord->setBxy(Bxy); // Set B field vector @@ -400,7 +401,7 @@ class GEM : public PhysicsModel { if (curv_logB) { Grad_par_logB = Grad_par(logB); } else { - Grad_par_logB = Grad_par(log(coord->Bxy)); + Grad_par_logB = Grad_par(log(coord->Bxy())); } } else { Grad_par_logB = 0.; @@ -1153,7 +1154,7 @@ class GEM : public PhysicsModel { if (curv_logB) { return -bracket(2. * logB, f, BRACKET_ARAKAWA); } - return -bracket(2. * log(coord->Bxy), f, BRACKET_ARAKAWA); + return -bracket(2. * log(coord->Bxy()), f, BRACKET_ARAKAWA); } //////////////////////////////////////////////////////////////////////// @@ -1168,7 +1169,7 @@ class GEM : public PhysicsModel { delp2.applyBoundary("neumann"); mesh->communicate(delp2); - return nu_perp * Delp2(delp2 * SQ(SQ(1. / coord->Bxy))) + return nu_perp * Delp2(delp2 * SQ(SQ(1. / coord->Bxy()))) - nu_par * Grad2_par2(f) // NB: This should be changed for variable B ; } @@ -1184,8 +1185,8 @@ class GEM : public PhysicsModel { } const Field3D Div_parP(const Field3D& f, CELL_LOC loc = CELL_DEFAULT) { - return interp_to(coord->Bxy, loc) - * Grad_parP(f / interp_to(coord->Bxy, f.getLocation()), loc); + return interp_to(coord->Bxy(), loc) + * Grad_parP(f / interp_to(coord->Bxy(), f.getLocation()), loc); } }; diff --git a/examples/laplace-petsc3d/test-laplace3d.cxx b/examples/laplace-petsc3d/test-laplace3d.cxx index 46bfce7859..5e40b42495 100644 --- a/examples/laplace-petsc3d/test-laplace3d.cxx +++ b/examples/laplace-petsc3d/test-laplace3d.cxx @@ -36,13 +36,13 @@ Field3D this_Laplace_perp(const Field3D& f) { // dfdy not divided by dy yet auto dfdy = bout::derivatives::index::DDY(f, CELL_DEFAULT, "DEFAULT", "RGN_NOY"); - return coords->G1 * DDX(f) - + (coords->G2 - DDY(coords->J / coords->g_22) / coords->J) * DDY(f) - + coords->G3 * DDZ(f) + coords->g11 * D2DX2(f) - + (coords->g22 - 1. / coords->g_22) * D2DY2(f) + coords->g33 * D2DZ2(f) + return coords->G1() * DDX(f) + + (coords->G2() - DDY(coords->J() / coords->g_22()) / coords->J()) * DDY(f) + + coords->G3() * DDZ(f) + coords->g11() * D2DX2(f) + + (coords->g22() - 1. / coords->g_22()) * D2DY2(f) + coords->g33() * D2DZ2(f) + 2. - * (coords->g12 * DDX(dfdy) / coords->dy + coords->g13 * D2DXDZ(f) - + coords->g23 * D2DYDZ(f)); + * (coords->g12() * DDX(dfdy) / coords->dy() + coords->g13() * D2DXDZ(f) + + coords->g23() * D2DYDZ(f)); } int main(int argc, char** argv) { @@ -136,7 +136,7 @@ int main(int argc, char** argv) { /////////////////////////////////////////////////////////////////////////////////////// // Calculate error /////////////////////////////////////////////////////////////////////////////////////// - auto& g_22 = mesh->getCoordinates()->g_22; + const auto& g_22 = mesh->getCoordinates()->g_22(); Field3D rhs_check = D * this_Laplace_perp(f) + (Grad(f) * Grad(C2) - DDY(C2) * DDY(f) / g_22) / C1 + A * f; // The usual way to do this would be diff --git a/examples/laplacexy/alfven-wave/alfven.cxx b/examples/laplacexy/alfven-wave/alfven.cxx index a4248afcf7..a4894e2cb5 100644 --- a/examples/laplacexy/alfven-wave/alfven.cxx +++ b/examples/laplacexy/alfven-wave/alfven.cxx @@ -179,7 +179,7 @@ class Alfven : public PhysicsModel { Field2D dx; if (!mesh->get(dx, "dpsi")) { output << "\tUsing dpsi as the x grid spacing\n"; - coord->dx = dx; // Only use dpsi if found + coord->setDx(dx); // Only use dpsi if found } else { // dx will have been read already from the grid output << "\tUsing dx as the x grid spacing\n"; @@ -188,11 +188,11 @@ class Alfven : public PhysicsModel { Rxy /= Lnorm; hthe /= Lnorm; sinty *= SQ(Lnorm) * Bnorm; - coord->dx /= SQ(Lnorm) * Bnorm; + coord->setDx(coord->dx() / (SQ(Lnorm) * Bnorm)); Bpxy /= Bnorm; Btxy /= Bnorm; - coord->Bxy /= Bnorm; + coord->setBxy(coord->Bxy() / Bnorm); // Calculate metric components sinty = 0.0; // I disappears from metric for shifted coordinates @@ -202,23 +202,24 @@ class Alfven : public PhysicsModel { sbp = -1.0; } - coord->g11 = SQ(Rxy * Bpxy); - coord->g22 = 1.0 / SQ(hthe); - coord->g33 = SQ(sinty) * coord->g11 + SQ(coord->Bxy) / coord->g11; - coord->g12 = 0.0; - coord->g13 = -sinty * coord->g11; - coord->g23 = -sbp * Btxy / (hthe * Bpxy * Rxy); + const auto g11 = SQ(Rxy * Bpxy); + const auto g22 = 1.0 / SQ(hthe); + const auto g33 = SQ(sinty) * g11 + SQ(coord->Bxy()) / g11; + const auto g12 = 0.0; + const auto g13 = -sinty * g11; + const auto g23 = -sbp * Btxy / (hthe * Bpxy * Rxy); - coord->J = hthe / Bpxy; + const auto g_11 = 1.0 / g11 + SQ(sinty * Rxy); + const auto g_22 = SQ(coord->Bxy() * hthe / Bpxy); + const auto g_33 = Rxy * Rxy; + const auto g_12 = sbp * Btxy * hthe * sinty * Rxy / Bpxy; + const auto g_13 = sinty * Rxy * Rxy; + const auto g_23 = sbp * Btxy * hthe * Rxy / Bpxy; - coord->g_11 = 1.0 / coord->g11 + SQ(sinty * Rxy); - coord->g_22 = SQ(coord->Bxy * hthe / Bpxy); - coord->g_33 = Rxy * Rxy; - coord->g_12 = sbp * Btxy * hthe * sinty * Rxy / Bpxy; - coord->g_13 = sinty * Rxy * Rxy; - coord->g_23 = sbp * Btxy * hthe * Rxy / Bpxy; + coord->setMetricTensor(ContravariantMetricTensor(g11, g22, g33, g12, g13, g23), + CovariantMetricTensor(g_11, g_22, g_33, g_12, g_13, g_23)); - coord->geometry(); + coord->setJ(hthe / Bpxy); } }; diff --git a/examples/laplacexy/laplace_perp/test.cxx b/examples/laplacexy/laplace_perp/test.cxx index 1312b005da..7b98f85ef5 100644 --- a/examples/laplacexy/laplace_perp/test.cxx +++ b/examples/laplacexy/laplace_perp/test.cxx @@ -25,24 +25,25 @@ int main(int argc, char** argv) { Coordinates* coord = mesh->getCoordinates(); // Calculate metrics - coord->g11 = SQ(Rxy * Bpxy); - coord->g22 = 1.0 / SQ(hthe); - coord->g33 = SQ(I) * coord->g11 + SQ(B0) / coord->g11; - coord->g12 = 0.0; - coord->g13 = -I * coord->g11; - coord->g23 = -Btxy / (hthe * Bpxy * Rxy); - - coord->J = hthe / Bpxy; - coord->Bxy = B0; - - coord->g_11 = 1.0 / coord->g11 + SQ(I * Rxy); - coord->g_22 = SQ(B0 * hthe / Bpxy); - coord->g_33 = Rxy * Rxy; - coord->g_12 = Btxy * hthe * I * Rxy / Bpxy; - coord->g_13 = I * Rxy * Rxy; - coord->g_23 = Btxy * hthe * Rxy / Bpxy; - - coord->geometry(); + const auto g11 = SQ(Rxy * Bpxy); + const auto g22 = 1.0 / SQ(hthe); + const auto g33 = SQ(I) * g11 + SQ(B0) / g11; + const auto g12 = 0.0; + const auto g13 = -I * g11; + const auto g23 = -Btxy / (hthe * Bpxy * Rxy); + + const auto g_11 = 1.0 / g11 + SQ(I * Rxy); + const auto g_22 = SQ(B0 * hthe / Bpxy); + const auto g_33 = Rxy * Rxy; + const auto g_12 = Btxy * hthe * I * Rxy / Bpxy; + const auto g_13 = I * Rxy * Rxy; + const auto g_23 = Btxy * hthe * Rxy / Bpxy; + + coord->setMetricTensor(ContravariantMetricTensor(g11, g22, g33, g12, g13, g23), + CovariantMetricTensor(g_11, g_22, g_33, g_12, g_13, g_23)); + + coord->setJ(hthe / Bpxy); + coord->setBxy(B0); } /////////////////////////////////////// diff --git a/examples/wave-slab/wave_slab.cxx b/examples/wave-slab/wave_slab.cxx index 4169b63dab..0bf4f1a9e7 100644 --- a/examples/wave-slab/wave_slab.cxx +++ b/examples/wave-slab/wave_slab.cxx @@ -21,7 +21,7 @@ class WaveTest : public PhysicsModel { GRID_LOAD(Bpxy); GRID_LOAD(Btxy); GRID_LOAD(hthe); - mesh->get(coords->Bxy, "Bxy"); + coords->setBxy(mesh->get("Bxy")); int ShiftXderivs = 0; mesh->get(ShiftXderivs, "false"); if (ShiftXderivs) { @@ -31,23 +31,24 @@ class WaveTest : public PhysicsModel { mesh->get(I, "sinty"); } - coords->g11 = pow(Rxy * Bpxy, 2.0); - coords->g22 = 1.0 / pow(hthe, 2.0); - coords->g33 = pow(I, 2.0) * coords->g11 + pow(coords->Bxy, 2.0) / coords->g11; - coords->g12 = 0.0; - coords->g13 = -I * coords->g11; - coords->g23 = -Btxy / (hthe * Bpxy * Rxy); + const auto g11 = pow(Rxy * Bpxy, 2.0); + const auto g22 = 1.0 / pow(hthe, 2.0); + const auto g33 = pow(I, 2.0) * g11 + pow(coords->Bxy(), 2.0) / g11; + const auto g12 = 0.0; + const auto g13 = -I * g11; + const auto g23 = -Btxy / (hthe * Bpxy * Rxy); - coords->J = hthe / Bpxy; + const auto g_11 = 1.0 / g11 + (pow(I * Rxy, 2.0)); + const auto g_22 = pow(coords->Bxy() * hthe / Bpxy, 2.0); + const auto g_33 = Rxy * Rxy; + const auto g_12 = Btxy * hthe * I * Rxy / Bpxy; + const auto g_13 = I * Rxy * Rxy; + const auto g_23 = Btxy * hthe * Rxy / Bpxy; - coords->g_11 = 1.0 / coords->g11 + (pow(I * Rxy, 2.0)); - coords->g_22 = pow(coords->Bxy * hthe / Bpxy, 2.0); - coords->g_33 = Rxy * Rxy; - coords->g_12 = Btxy * hthe * I * Rxy / Bpxy; - coords->g_13 = I * Rxy * Rxy; - coords->g_23 = Btxy * hthe * Rxy / Bpxy; + coords->setMetricTensor(ContravariantMetricTensor(g11, g22, g33, g12, g13, g23), + CovariantMetricTensor(g_11, g_22, g_33, g_12, g_13, g_23)); - coords->geometry(); + coords->setJ(hthe / Bpxy); solver->add(f, "f"); solver->add(g, "g"); diff --git a/include/bout/christoffel_symbols.hxx b/include/bout/christoffel_symbols.hxx new file mode 100644 index 0000000000..0e0459eb9a --- /dev/null +++ b/include/bout/christoffel_symbols.hxx @@ -0,0 +1,69 @@ + +#ifndef BOUT_CHRISTOFFELSYMBOLS_HXX +#define BOUT_CHRISTOFFELSYMBOLS_HXX + +#include "bout/field2d.hxx" +#include "bout/field3d.hxx" +#include "bout/metric_tensor.hxx" +#include + +using FieldMetric = MetricTensor::FieldMetric; + +class Coordinates; + +class ChristoffelSymbols { + +public: + explicit ChristoffelSymbols(Coordinates& coordinates); + + const FieldMetric& G1_11() const { return G1_11_m; } + const FieldMetric& G1_22() const { return G1_22_m; } + const FieldMetric& G1_33() const { return G1_33_m; } + const FieldMetric& G1_12() const { return G1_12_m; } + const FieldMetric& G1_13() const { return G1_13_m; } + const FieldMetric& G1_23() const { return G1_23_m; } + + const FieldMetric& G2_11() const { return G2_11_m; } + const FieldMetric& G2_22() const { return G2_22_m; } + const FieldMetric& G2_33() const { return G2_33_m; } + const FieldMetric& G2_12() const { return G2_12_m; } + const FieldMetric& G2_13() const { return G2_13_m; } + const FieldMetric& G2_23() const { return G2_23_m; } + + const FieldMetric& G3_11() const { return G3_11_m; } + const FieldMetric& G3_22() const { return G3_22_m; } + const FieldMetric& G3_33() const { return G3_33_m; } + const FieldMetric& G3_12() const { return G3_12_m; } + const FieldMetric& G3_13() const { return G3_13_m; } + const FieldMetric& G3_23() const { return G3_23_m; } + + // Transforms the ChristoffelSymbols by applying the given function to every element + template + void map(F function) { + G1_11_m = function(G1_11_m); + G1_22_m = function(G1_22_m); + G1_33_m = function(G1_33_m); + G1_12_m = function(G1_12_m); + G1_13_m = function(G1_13_m); + G1_23_m = function(G1_23_m); + G2_11_m = function(G2_11_m); + G2_22_m = function(G2_22_m); + G2_33_m = function(G2_33_m); + G2_12_m = function(G2_12_m); + G2_13_m = function(G2_13_m); + G2_23_m = function(G2_23_m); + G3_11_m = function(G3_11_m); + G3_22_m = function(G3_22_m); + G3_33_m = function(G3_33_m); + G3_12_m = function(G3_12_m); + G3_13_m = function(G3_13_m); + G3_23_m = function(G3_23_m); + } + +private: + FieldMetric G1_11_m, G1_22_m, G1_33_m, G1_12_m, G1_13_m, G1_23_m; + FieldMetric G2_11_m, G2_22_m, G2_33_m, G2_12_m, G2_13_m, G2_23_m; + FieldMetric G3_11_m, G3_22_m, G3_33_m, G3_12_m, G3_13_m, G3_23_m; +}; + +#endif //BOUT_CHRISTOFFELSYMBOLS_HXX diff --git a/include/bout/coordinates.hxx b/include/bout/coordinates.hxx index 49feffa0a7..d100e2d797 100644 --- a/include/bout/coordinates.hxx +++ b/include/bout/coordinates.hxx @@ -33,18 +33,15 @@ #ifndef BOUT_COORDINATES_H #define BOUT_COORDINATES_H -#include "bout/field2d.hxx" -#include "bout/field3d.hxx" +#include "christoffel_symbols.hxx" +#include "g_values.hxx" +#include "bout/metric_tensor.hxx" #include "bout/paralleltransform.hxx" -#include "bout/utils.hxx" -#include class Mesh; /*! * Represents a coordinate system, and associated operators - * - * This is a container for a collection of metric tensor components */ class Coordinates { public: @@ -54,74 +51,209 @@ public: using FieldMetric = Field2D; #endif - /// Standard constructor from input - Coordinates(Mesh* mesh, Options* options = nullptr); - /// Constructor interpolating from another Coordinates object /// By default attempts to read staggered Coordinates from grid data source, /// interpolating from CELL_CENTRE if not present. Set /// force_interpolate_from_centre argument to true to always interpolate /// (useful if CELL_CENTRE Coordinates have been changed, so reading from file /// would not be correct). - Coordinates(Mesh* mesh, Options* options, const CELL_LOC loc, - const Coordinates* coords_in, bool force_interpolate_from_centre = false); + explicit Coordinates(Mesh* mesh, Options* options = nullptr, CELL_LOC loc = CELL_CENTRE, + const Coordinates* coords_in = nullptr, + bool force_interpolate_from_centre = false); /// A constructor useful for testing purposes. To use it, inherit /// from Coordinates. If \p calculate_geometry is true (default), /// calculate the non-uniform variables, Christoffel symbols - Coordinates(Mesh* mesh, FieldMetric dx, FieldMetric dy, FieldMetric dz, FieldMetric J, - FieldMetric Bxy, FieldMetric g11, FieldMetric g22, FieldMetric g33, - FieldMetric g12, FieldMetric g13, FieldMetric g23, FieldMetric g_11, - FieldMetric g_22, FieldMetric g_33, FieldMetric g_12, FieldMetric g_13, - FieldMetric g_23, FieldMetric ShiftTorsion, FieldMetric IntShiftTorsion); - - Coordinates& operator=(Coordinates&&) = default; - - ~Coordinates() = default; + Coordinates(Mesh* mesh, FieldMetric dx, FieldMetric dy, FieldMetric dz, + [[maybe_unused]] const FieldMetric& J, FieldMetric Bxy, + const FieldMetric& g11, const FieldMetric& g22, const FieldMetric& g33, + const FieldMetric& g12, const FieldMetric& g13, const FieldMetric& g23, + const FieldMetric& g_11, const FieldMetric& g_22, const FieldMetric& g_33, + const FieldMetric& g_12, const FieldMetric& g_13, const FieldMetric& g_23, + FieldMetric ShiftTorsion, FieldMetric IntShiftTorsion); /// Add variables to \p output_options, for post-processing void outputVars(Options& output_options); - FieldMetric dx, dy, dz; ///< Mesh spacing in x, y and z + ///< Mesh spacing in x, y and z + const FieldMetric& dx() const { return dx_; } + const FieldMetric& dy() const { return dy_; } + const FieldMetric& dz() const { return dz_; } + + const BoutReal& dx(int x, int y, int z) const { return dx_(x, y, z); } + const BoutReal& dy(int x, int y, int z) const { return dy_(x, y, z); } + const BoutReal& dz(int x, int y, int z) const { return dz_(x, y, z); } + +#if BOUT_USE_METRIC_3D + const BoutReal* dx(int x, int y) const { return dx_(x, y); } + const BoutReal* dy(int x, int y) const { return dy_(x, y); } + const BoutReal* dz(int x, int y) const { return dz_(x, y); } +#else + const BoutReal& dx(int x, int y) const { return dx_(x, y); } + const BoutReal& dy(int x, int y) const { return dy_(x, y); } + const BoutReal& dz(int x, int y) const { return dz_(x, y); } +#endif + + const BoutReal& IntShiftTorsion(int x, int y, int z) const { + return IntShiftTorsion_(x, y, z); + } + +#if not(BOUT_USE_METRIC_3D) + const BoutReal& IntShiftTorsion(int x, int y) const { return IntShiftTorsion_(x, y); } +#endif + + const BoutReal& J(int x, int y, int z) const { return J()(x, y, z); } + +#if not(BOUT_USE_METRIC_3D) + const BoutReal& J(int x, int y) const { return J()(x, y); } +#endif + + void setDx(FieldMetric dx); + void setDy(FieldMetric dy); + void setDz(FieldMetric dz); + + void setD1_dx(FieldMetric d1_dx) { d1_dx_ = std::move(d1_dx); } + void setD1_dy(FieldMetric d1_dy) { d1_dy_ = std::move(d1_dy); } + void setD1_dz(FieldMetric d1_dz) { d1_dz_ = std::move(d1_dz); } /// Length of the Z domain. Used for FFTs const Field2D& zlength() const; + const BoutReal& zlength(int x, int y) const { return zlength()(x, y); } + /// True if corrections for non-uniform mesh spacing should be included in operators - bool non_uniform; + bool non_uniform() const { return non_uniform_; } + void setNon_uniform(bool non_uniform) { non_uniform_ = non_uniform; } + /// 2nd-order correction for non-uniform meshes d/di(1/dx), d/di(1/dy) and d/di(1/dz) - FieldMetric d1_dx, d1_dy, d1_dz; + const FieldMetric& d1_dx() const { return d1_dx_; } + const FieldMetric& d1_dy() const { return d1_dy_; } + const FieldMetric& d1_dz() const { return d1_dz_; } - FieldMetric J; ///< Coordinate system Jacobian, so volume of cell is J*dx*dy*dz +#if BOUT_USE_METRIC_3D + const BoutReal& d1_dx(int x, int y, int z) const { return d1_dx_(x, y, z); } + const BoutReal& d1_dy(int x, int y, int z) const { return d1_dy_(x, y, z); } + const BoutReal& d1_dz(int x, int y, int z) const { return d1_dz_(x, y, z); } +#else + const BoutReal& d1_dx(int x, int y) const { return d1_dx_(x, y); } + const BoutReal& d1_dy(int x, int y) const { return d1_dy_(x, y); } + const BoutReal& d1_dz(int x, int y) const { return d1_dz_(x, y); } +#endif - FieldMetric Bxy; ///< Magnitude of B = nabla z times nabla x + /// Covariant metric tensor + const MetricTensor::FieldMetric& g_11() const { return covariantMetricTensor.g11(); } + const MetricTensor::FieldMetric& g_22() const { return covariantMetricTensor.g22(); } + const MetricTensor::FieldMetric& g_33() const { return covariantMetricTensor.g33(); } + const MetricTensor::FieldMetric& g_12() const { return covariantMetricTensor.g12(); } + const MetricTensor::FieldMetric& g_13() const { return covariantMetricTensor.g13(); } + const MetricTensor::FieldMetric& g_23() const { return covariantMetricTensor.g23(); } /// Contravariant metric tensor (g^{ij}) - FieldMetric g11, g22, g33, g12, g13, g23; + const MetricTensor::FieldMetric& g11() const { return contravariantMetricTensor.g11(); } + const MetricTensor::FieldMetric& g22() const { return contravariantMetricTensor.g22(); } + const MetricTensor::FieldMetric& g33() const { return contravariantMetricTensor.g33(); } + const MetricTensor::FieldMetric& g12() const { return contravariantMetricTensor.g12(); } + const MetricTensor::FieldMetric& g13() const { return contravariantMetricTensor.g13(); } + const MetricTensor::FieldMetric& g23() const { return contravariantMetricTensor.g23(); } /// Covariant metric tensor - FieldMetric g_11, g_22, g_33, g_12, g_13, g_23; + const BoutReal& g_11(int x, int y, int z) const { + return covariantMetricTensor.g11(x, y, z); + } + const BoutReal& g_22(int x, int y, int z) const { + return covariantMetricTensor.g22(x, y, z); + } + const BoutReal& g_33(int x, int y, int z) const { + return covariantMetricTensor.g33(x, y, z); + } + const BoutReal& g_12(int x, int y, int z) const { + return covariantMetricTensor.g12(x, y, z); + } + const BoutReal& g_13(int x, int y, int z) const { + return covariantMetricTensor.g13(x, y, z); + } + const BoutReal& g_23(int x, int y, int z) const { + return covariantMetricTensor.g23(x, y, z); + } - /// Christoffel symbol of the second kind (connection coefficients) - FieldMetric G1_11, G1_22, G1_33, G1_12, G1_13, G1_23; - FieldMetric G2_11, G2_22, G2_33, G2_12, G2_13, G2_23; - FieldMetric G3_11, G3_22, G3_33, G3_12, G3_13, G3_23; +#if not(BOUT_USE_METRIC_3D) + const BoutReal& g_11(int x, int y) const { return covariantMetricTensor.g11(x, y); } + const BoutReal& g_22(int x, int y) const { return covariantMetricTensor.g22(x, y); } + const BoutReal& g_33(int x, int y) const { return covariantMetricTensor.g33(x, y); } + const BoutReal& g_12(int x, int y) const { return covariantMetricTensor.g12(x, y); } + const BoutReal& g_13(int x, int y) const { return covariantMetricTensor.g13(x, y); } + const BoutReal& g_23(int x, int y) const { return covariantMetricTensor.g23(x, y); } +#endif + + /// Contravariant metric tensor (g^{ij}) + const BoutReal& g11(int x, int y, int z) const { + return contravariantMetricTensor.g11(x, y, z); + } + const BoutReal& g22(int x, int y, int z) const { + return contravariantMetricTensor.g22(x, y, z); + } + const BoutReal& g33(int x, int y, int z) const { + return contravariantMetricTensor.g33(x, y, z); + } + const BoutReal& g12(int x, int y, int z) const { + return contravariantMetricTensor.g12(x, y, z); + } + const BoutReal& g13(int x, int y, int z) const { + return contravariantMetricTensor.g13(x, y, z); + } + const BoutReal& g23(int x, int y, int z) const { + return contravariantMetricTensor.g23(x, y, z); + } + +#if BOUT_USE_METRIC_3D != 1 + const BoutReal& g11(int x, int y) const { return contravariantMetricTensor.g11(x, y); } + const BoutReal& g22(int x, int y) const { return contravariantMetricTensor.g22(x, y); } + const BoutReal& g33(int x, int y) const { return contravariantMetricTensor.g33(x, y); } + const BoutReal& g12(int x, int y) const { return contravariantMetricTensor.g12(x, y); } + const BoutReal& g13(int x, int y) const { return contravariantMetricTensor.g13(x, y); } + const BoutReal& g23(int x, int y) const { return contravariantMetricTensor.g23(x, y); } +#endif + + const ContravariantMetricTensor& getContravariantMetricTensor() const { + return contravariantMetricTensor; + } + + const CovariantMetricTensor& getCovariantMetricTensor() const { + return covariantMetricTensor; + } + + void setContravariantMetricTensor(const ContravariantMetricTensor& metric_tensor, + const std::string& region = "RGN_ALL", + bool recalculate_staggered = true, + bool force_interpolate_from_centre = false); + + void setCovariantMetricTensor(const CovariantMetricTensor& metric_tensor, + const std::string& region = "RGN_ALL", + bool recalculate_staggered = true, + bool force_interpolate_from_centre = false); + + void setMetricTensor(const ContravariantMetricTensor& contravariant_metric_tensor, + const CovariantMetricTensor& covariant_metric_tensor); + + ///< Coordinate system Jacobian, so volume of cell is J*dx*dy*dz + FieldMetric& J() const; + + ///< Magnitude of B = nabla z times nabla x + const FieldMetric& Bxy() const { return Bxy_; } + + void setJ(const FieldMetric& J); - FieldMetric G1, G2, G3; + void setBxy(FieldMetric Bxy); /// d pitch angle / dx. Needed for vector differentials (Curl) - FieldMetric ShiftTorsion; + const FieldMetric& ShiftTorsion() const { return ShiftTorsion_; } - FieldMetric IntShiftTorsion; ///< Integrated shear (I in BOUT notation) + ///< Integrated shear (I in BOUT notation) + const FieldMetric& IntShiftTorsion() const { return IntShiftTorsion_; } - /// Calculate differential geometry quantities from the metric tensor - int geometry(bool recalculate_staggered = true, - bool force_interpolate_from_centre = false); - /// Invert contravatiant metric to get covariant components - int calcCovariant(const std::string& region = "RGN_ALL"); - /// Invert covariant metric to get contravariant components - int calcContravariant(const std::string& region = "RGN_ALL"); - int jacobian(); ///< Calculate J and Bxy + void setIntShiftTorsion(FieldMetric IntShiftTorsion) { + IntShiftTorsion_ = std::move(IntShiftTorsion); + } /////////////////////////////////////////////////////////// // Parallel transforms @@ -145,7 +277,7 @@ public: FieldMetric DDX(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", - const std::string& region = "RGN_NOBNDRY"); + const std::string& region = "RGN_NOBNDRY") const; FieldMetric DDY(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", @@ -153,11 +285,11 @@ public: FieldMetric DDZ(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", - const std::string& region = "RGN_NOBNDRY"); + const std::string& region = "RGN_NOBNDRY") const; Field3D DDX(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", - const std::string& region = "RGN_NOBNDRY"); + const std::string& region = "RGN_NOBNDRY") const; Field3D DDY(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", @@ -165,7 +297,7 @@ public: Field3D DDZ(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", - const std::string& region = "RGN_NOBNDRY"); + const std::string& region = "RGN_NOBNDRY") const; /// Gradient along magnetic field b.Grad(f) FieldMetric Grad_par(const Field2D& var, CELL_LOC outloc = CELL_DEFAULT, @@ -218,36 +350,148 @@ public: // Full perpendicular Laplacian, in form of inverse of Laplacian operator in LaplaceXY // solver - Field2D Laplace_perpXY(const Field2D& A, const Field2D& f); + Field2D Laplace_perpXY(const Field2D& A, const Field2D& f) const; + + /// Christoffel symbol of the second kind (connection coefficients) + const FieldMetric& G1_11() { return christoffel_symbols().G1_11(); } + const FieldMetric& G1_22() { return christoffel_symbols().G1_22(); } + const FieldMetric& G1_33() { return christoffel_symbols().G1_33(); } + const FieldMetric& G1_12() { return christoffel_symbols().G1_12(); } + const FieldMetric& G1_13() { return christoffel_symbols().G1_13(); } + const FieldMetric& G1_23() { return christoffel_symbols().G1_23(); } + const FieldMetric& G2_11() { return christoffel_symbols().G2_11(); } + const FieldMetric& G2_22() { return christoffel_symbols().G2_22(); } + const FieldMetric& G2_33() { return christoffel_symbols().G2_33(); } + const FieldMetric& G2_12() { return christoffel_symbols().G2_12(); } + const FieldMetric& G2_13() { return christoffel_symbols().G2_13(); } + const FieldMetric& G2_23() { return christoffel_symbols().G2_23(); } + const FieldMetric& G3_11() { return christoffel_symbols().G3_11(); } + const FieldMetric& G3_22() { return christoffel_symbols().G3_22(); } + const FieldMetric& G3_33() { return christoffel_symbols().G3_33(); } + const FieldMetric& G3_12() { return christoffel_symbols().G3_12(); } + const FieldMetric& G3_13() { return christoffel_symbols().G3_13(); } + const FieldMetric& G3_23() { return christoffel_symbols().G3_23(); } + + const FieldMetric& G1() const { return g_values().G1(); } + const FieldMetric& G2() const { return g_values().G2(); } + const FieldMetric& G3() const { return g_values().G3(); } + + const BoutReal& G1(int x, int y, int z) const { return G1()(x, y, z); } + const BoutReal& G2(int x, int y, int z) const { return G2()(x, y, z); } + const BoutReal& G3(int x, int y, int z) const { return G3()(x, y, z); } + +#if not(BOUT_USE_METRIC_3D) + const BoutReal& G1(int x, int y) const { return G1()(x, y); } + const BoutReal& G2(int x, int y) const { return G2()(x, y); } + const BoutReal& G3(int x, int y) const { return G3()(x, y); } +#endif + + const FieldMetric& Grad2_par2_DDY_invSg(CELL_LOC outloc, + const std::string& method) const; + + const FieldMetric& invSg() const; + + ChristoffelSymbols& christoffel_symbols(); + + GValues& g_values() const; + + void recalculateAndReset(bool recalculate_staggered, + bool force_interpolate_from_centre); + + FieldMetric recalculateJacobian() const; + + static void communicate(Field2D& f); + +#if BOUT_USE_METRIC_3D + // In this case we also need to be able to call with a Field3D + static void communicate(Field3D& f); +#endif private: int nz; // Size of mesh in Z. This is mesh->ngz-1 Mesh* localmesh; CELL_LOC location; + /// True if corrections for non-uniform mesh spacing should be included in operators + bool non_uniform_{}; + + FieldMetric dx_, dy_, dz_; ///< Mesh spacing in x, y and z + + /// 2nd-order correction for non-uniform meshes d/di(1/dx), d/di(1/dy) and d/di(1/dz) + FieldMetric d1_dx_, d1_dy_, d1_dz_; + + /// d pitch angle / dx. Needed for vector differentials (Curl) + FieldMetric ShiftTorsion_; + + ///< Integrated shear (I in BOUT notation) + FieldMetric IntShiftTorsion_; + /// Handles calculation of yup and ydown std::unique_ptr transform{nullptr}; /// Cache variable for `zlength`. Invalidated when - /// `Coordinates::geometry` is called + /// `Coordinates::recalculateAndReset` is called mutable std::unique_ptr zlength_cache{nullptr}; /// Cache variable for Grad2_par2 mutable std::map> Grad2_par2_DDY_invSgCache; mutable std::unique_ptr invSgCache{nullptr}; + ContravariantMetricTensor contravariantMetricTensor; + CovariantMetricTensor covariantMetricTensor; + + /// Christoffel symbol of the second kind (connection coefficients) + mutable std::unique_ptr christoffel_symbols_cache{nullptr}; + + /// `g_values` needs renaming, when we know what the name should be + mutable std::unique_ptr g_values_cache{nullptr}; + + mutable std::unique_ptr jacobian_cache{nullptr}; + + FieldMetric Bxy_; ///< Magnitude of B = nabla z times nabla x + /// Set the parallel (y) transform from the options file. /// Used in the constructor to create the transform object. void setParallelTransform(Options* options); - const FieldMetric& invSg() const; - const FieldMetric& Grad2_par2_DDY_invSg(CELL_LOC outloc, - const std::string& method) const; - // check that covariant tensors are positive (if expected) and finite (always) void checkCovariant(); // check that contravariant tensors are positive (if expected) and finite (always) void checkContravariant(); + + FieldMetric getAtLocOrUnaligned(Mesh* mesh, const std::string& name, + BoutReal default_value = 0., + const std::string& suffix = "", + CELL_LOC cell_location = CELL_CENTRE); + + FieldMetric getUnaligned(const std::string& name, BoutReal default_value); + + FieldMetric recalculateBxy() const; + + /// Non-uniform meshes. Need to use DDX, DDY + void correctionForNonUniformMeshes(bool force_interpolate_from_centre); + + void interpolateFromCoordinates(Options* options, const Coordinates* coords_in); + + void readFromMesh(Options* options, const std::string& suffix); + + FieldMetric getDzFromOptionsFile(Mesh* mesh, const std::string& suffix) const; + + void fixZShiftGuards(Field2D& zShift) const; + + static Field2D interpolateAndExtrapolate(const Field2D& f, CELL_LOC location, + bool extrapolate_x, bool extrapolate_y, + bool no_extra_interpolate, + ParallelTransform* UNUSED_pt, + const std::string& region); + +#if BOUT_USE_METRIC_3D + static Field3D interpolateAndExtrapolate(const Field3D& f_, CELL_LOC location, + bool extrapolate_x, bool extrapolate_y, + bool no_extra_interpolate, + ParallelTransform* pt_); + +#endif // BOUT_USE_METRIC_3D }; /* diff --git a/include/bout/fv_ops.hxx b/include/bout/fv_ops.hxx index 94007a57a2..612d61436e 100644 --- a/include/bout/fv_ops.hxx +++ b/include/bout/fv_ops.hxx @@ -406,10 +406,10 @@ const Field3D Div_f_v(const Field3D& n_in, const Vector3D& v, bool bndry_flux) { BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { // Calculate velocities - BoutReal vU = 0.25 * (vz[i.zp()] + vz[i]) * (coord->J[i.zp()] + coord->J[i]); - BoutReal vD = 0.25 * (vz[i.zm()] + vz[i]) * (coord->J[i.zm()] + coord->J[i]); - BoutReal vL = 0.25 * (vx[i.xm()] + vx[i]) * (coord->J[i.xm()] + coord->J[i]); - BoutReal vR = 0.25 * (vx[i.xp()] + vx[i]) * (coord->J[i.xp()] + coord->J[i]); + BoutReal vU = 0.25 * (vz[i.zp()] + vz[i]) * (coord->J()[i.zp()] + coord->J()[i]); + BoutReal vD = 0.25 * (vz[i.zm()] + vz[i]) * (coord->J()[i.zm()] + coord->J()[i]); + BoutReal vL = 0.25 * (vx[i.xm()] + vx[i]) * (coord->J()[i.xm()] + coord->J()[i]); + BoutReal vR = 0.25 * (vx[i.xp()] + vx[i]) * (coord->J()[i.xp()] + coord->J()[i]); // X direction Stencil1D s; @@ -432,16 +432,16 @@ const Field3D Div_f_v(const Field3D& n_in, const Vector3D& v, bool bndry_flux) { // Flux in from boundary flux = vR * 0.5 * (n[i.xp()] + n[i]); } - result[i] += flux / (coord->dx[i] * coord->J[i]); - result[i.xp()] -= flux / (coord->dx[i.xp()] * coord->J[i.xp()]); + result[i] += flux / (coord->dx()[i] * coord->J()[i]); + result[i.xp()] -= flux / (coord->dx()[i.xp()] * coord->J()[i.xp()]); } } else { // Not at a boundary if (vR > 0.0) { // Flux out into next cell BoutReal flux = vR * s.R; - result[i] += flux / (coord->dx[i] * coord->J[i]); - result[i.xp()] -= flux / (coord->dx[i.xp()] * coord->J[i.xp()]); + result[i] += flux / (coord->dx()[i] * coord->J()[i]); + result[i.xp()] -= flux / (coord->dx()[i.xp()] * coord->J()[i.xp()]); } } @@ -459,15 +459,15 @@ const Field3D Div_f_v(const Field3D& n_in, const Vector3D& v, bool bndry_flux) { // Flux in from boundary flux = vL * 0.5 * (n[i.xm()] + n[i]); } - result[i] -= flux / (coord->dx[i] * coord->J[i]); - result[i.xm()] += flux / (coord->dx[i.xm()] * coord->J[i.xm()]); + result[i] -= flux / (coord->dx()[i] * coord->J()[i]); + result[i.xm()] += flux / (coord->dx()[i.xm()] * coord->J()[i.xm()]); } } else { // Not at a boundary if (vL < 0.0) { BoutReal flux = vL * s.L; - result[i] -= flux / (coord->dx[i] * coord->J[i]); - result[i.xm()] += flux / (coord->dx[i.xm()] * coord->J[i.xm()]); + result[i] -= flux / (coord->dx()[i] * coord->J()[i]); + result[i.xm()] += flux / (coord->dx()[i.xm()] * coord->J()[i.xm()]); } } @@ -483,13 +483,13 @@ const Field3D Div_f_v(const Field3D& n_in, const Vector3D& v, bool bndry_flux) { if (vU > 0.0) { BoutReal flux = vU * s.R; - result[i] += flux / (coord->J[i] * coord->dz[i]); - result[i.zp()] -= flux / (coord->J[i.zp()] * coord->dz[i.zp()]); + result[i] += flux / (coord->J()[i] * coord->dz()[i]); + result[i.zp()] -= flux / (coord->J()[i.zp()] * coord->dz()[i.zp()]); } if (vD < 0.0) { BoutReal flux = vD * s.L; - result[i] -= flux / (coord->J[i] * coord->dz[i]); - result[i.zm()] += flux / (coord->J[i.zm()] * coord->dz[i.zm()]); + result[i] -= flux / (coord->J()[i] * coord->dz()[i]); + result[i.zm()] += flux / (coord->J()[i.zm()] * coord->dz()[i.zm()]); } } @@ -507,15 +507,15 @@ const Field3D Div_f_v(const Field3D& n_in, const Vector3D& v, bool bndry_flux) { BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { // Y velocities on y boundaries - BoutReal vU = 0.25 * (vy[i] + vy[i.yp()]) * (coord->J[i] + coord->J[i.yp()]); - BoutReal vD = 0.25 * (vy[i] + vy[i.ym()]) * (coord->J[i] + coord->J[i.ym()]); + BoutReal vU = 0.25 * (vy[i] + vy[i.yp()]) * (coord->J()[i] + coord->J()[i.yp()]); + BoutReal vD = 0.25 * (vy[i] + vy[i.ym()]) * (coord->J()[i] + coord->J()[i.ym()]); // n (advected quantity) on y boundaries // Note: Use unshifted n_in variable BoutReal nU = 0.5 * (n[i] + n[i.yp()]); BoutReal nD = 0.5 * (n[i] + n[i.ym()]); - yresult[i] = (nU * vU - nD * vD) / (coord->J[i] * coord->dy[i]); + yresult[i] = (nU * vU - nD * vD) / (coord->J()[i] * coord->dy()[i]); } return result + fromFieldAligned(yresult, "RGN_NOBNDRY"); } diff --git a/include/bout/g_values.hxx b/include/bout/g_values.hxx new file mode 100644 index 0000000000..eac2194bd3 --- /dev/null +++ b/include/bout/g_values.hxx @@ -0,0 +1,29 @@ + +#ifndef BOUT_GVALUES_HXX +#define BOUT_GVALUES_HXX + +#include "bout/metric_tensor.hxx" + +using FieldMetric = MetricTensor::FieldMetric; + +/// `GValues` needs renaming, when we know what the name should be +class GValues { +public: + explicit GValues(const Coordinates& coordinates); + + const FieldMetric& G1() const { return G1_m; } + const FieldMetric& G2() const { return G2_m; } + const FieldMetric& G3() const { return G3_m; } + + template + void map(F function) { + G1_m = function(G1_m); + G2_m = function(G2_m); + G3_m = function(G3_m); + } + +private: + FieldMetric G1_m, G2_m, G3_m; +}; + +#endif //BOUT_GVALUES_HXX diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index c80716fc12..e2437535ba 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -192,6 +192,20 @@ public: int get(Field2D& var, const std::string& name, BoutReal def = 0.0, bool communicate = true, CELL_LOC location = CELL_DEFAULT); + /// Get a Field2D from the input source + /// including communicating guard cells. + /// This is a new version of the `get` function, that returns the value + /// avoiding the use of an out parameter. + /// Also returns a new Field2D rather than a reference to one + /// + /// @param[in] name Name of the variable to read + /// @param[in] def The default value if not found + /// @param[in] communicate Should the field be communicated to fill guard cells? + /// + /// @returns the value. Will be allocated if needed + Coordinates::FieldMetric get(const std::string& name, BoutReal def = 0.0, + bool communicate = true, CELL_LOC location = CELL_DEFAULT); + /// Get a Field3D from the input source /// /// @param[out] var This will be set to the value. Will be allocated if needed @@ -631,8 +645,14 @@ public: // Note that this can't be allocated here due to incomplete type // (circular dependency between Mesh and Coordinates) auto inserted = coords_map.emplace(location, nullptr); - inserted.first->second = createDefaultCoordinates(location); - inserted.first->second->geometry(false); + auto force_interpolate_from_centre = false; + inserted.first->second = + createDefaultCoordinates(location, force_interpolate_from_centre); + + auto recalculate_staggered = false; + inserted.first->second->recalculateAndReset(recalculate_staggered, + force_interpolate_from_centre); + return inserted.first->second; } @@ -705,8 +725,7 @@ public: /// Determines the resultant output stagger location in derivatives /// given the input and output location. Also checks that the /// combination of locations is allowed - STAGGER getStagger(const CELL_LOC inloc, const CELL_LOC outloc, - const CELL_LOC allowedloc) const; + STAGGER getStagger(CELL_LOC inloc, CELL_LOC outloc, CELL_LOC allowedloc) const; /// Determines the resultant output stagger location in derivatives /// given the input and output location. Also checks that the @@ -837,8 +856,7 @@ private: /// (useful if CELL_CENTRE Coordinates have been changed, so reading from file /// would not be correct). std::shared_ptr - createDefaultCoordinates(const CELL_LOC location, - bool force_interpolate_from_centre = false); + createDefaultCoordinates(CELL_LOC location, bool force_interpolate_from_centre = false); //Internal region related information std::map regionMap3D; diff --git a/include/bout/metric_tensor.hxx b/include/bout/metric_tensor.hxx new file mode 100644 index 0000000000..38c7d7e775 --- /dev/null +++ b/include/bout/metric_tensor.hxx @@ -0,0 +1,109 @@ + +#ifndef BOUT_METRIC_TENSOR_HXX +#define BOUT_METRIC_TENSOR_HXX + +#include "bout/build_defines.hxx" +#include "bout/field2d.hxx" +#include "bout/field3d.hxx" +#include + +#include +#include + +class MetricTensor { + +public: +#if BOUT_USE_METRIC_3D + using FieldMetric = Field3D; + using Metric2DSlice = const BoutReal*; +#else + using FieldMetric = Field2D; + using Metric2DSlice = const BoutReal&; +#endif + + MetricTensor(FieldMetric g11, FieldMetric g22, FieldMetric g33, FieldMetric g12, + FieldMetric g13, FieldMetric g23); + + MetricTensor(BoutReal g11, BoutReal g22, BoutReal g33, BoutReal g12, BoutReal g13, + BoutReal g23, Mesh* mesh); + + // check that tensors are positive (if expected) and finite (always) + void check(int ystart); + + const FieldMetric& g11() const { return g11_m; } + const FieldMetric& g22() const { return g22_m; } + const FieldMetric& g33() const { return g33_m; } + const FieldMetric& g12() const { return g12_m; } + const FieldMetric& g13() const { return g13_m; } + const FieldMetric& g23() const { return g23_m; } + + const BoutReal& g11(int x, int y, int z) const { return g11_m(x, y, z); } + const BoutReal& g22(int x, int y, int z) const { return g22_m(x, y, z); } + const BoutReal& g33(int x, int y, int z) const { return g33_m(x, y, z); } + const BoutReal& g12(int x, int y, int z) const { return g12_m(x, y, z); } + const BoutReal& g13(int x, int y, int z) const { return g13_m(x, y, z); } + const BoutReal& g23(int x, int y, int z) const { return g23_m(x, y, z); } + + Metric2DSlice g11(int x, int y) const { return g11_m(x, y); } + Metric2DSlice g22(int x, int y) const { return g22_m(x, y); } + Metric2DSlice g33(int x, int y) const { return g33_m(x, y); } + Metric2DSlice g12(int x, int y) const { return g12_m(x, y); } + Metric2DSlice g13(int x, int y) const { return g13_m(x, y); } + Metric2DSlice g23(int x, int y) const { return g23_m(x, y); } + + void setMetricTensor(const MetricTensor& metric_tensor) { + + g11_m = metric_tensor.g11(); + g22_m = metric_tensor.g22(); + g33_m = metric_tensor.g33(); + g12_m = metric_tensor.g12(); + g13_m = metric_tensor.g13(); + g23_m = metric_tensor.g23(); + } + + MetricTensor inverse(const std::string& region = "RGN_ALL"); + + // Transforms the MetricTensor by applying the given function to every component + template + void map(F function) { + g11_m = function(g11_m); + g22_m = function(g22_m); + g33_m = function(g33_m); + g12_m = function(g12_m); + g13_m = function(g13_m); + g23_m = function(g23_m); + } + +private: + FieldMetric g11_m, g22_m, g33_m, g12_m, g13_m, g23_m; +}; + +class CovariantMetricTensor : public MetricTensor { + +public: + CovariantMetricTensor(FieldMetric g11, FieldMetric g22, FieldMetric g33, + FieldMetric g12, FieldMetric g13, FieldMetric g23) + : MetricTensor(std::move(g11), std::move(g22), std::move(g33), std::move(g12), + std::move(g13), std::move(g23)){}; + + CovariantMetricTensor(const BoutReal g11, const BoutReal g22, const BoutReal g33, + const BoutReal g12, const BoutReal g13, const BoutReal g23, + Mesh* mesh) + : MetricTensor(g11, g22, g33, g12, g13, g23, mesh){}; +}; + +class ContravariantMetricTensor : public MetricTensor { + +public: + ContravariantMetricTensor(FieldMetric g_11, FieldMetric g_22, FieldMetric g_33, + FieldMetric g_12, FieldMetric g_13, FieldMetric g_23) + : MetricTensor(std::move(g_11), std::move(g_22), std::move(g_33), std::move(g_12), + std::move(g_13), std::move(g_23)){}; + + ContravariantMetricTensor(const BoutReal g_11, const BoutReal g_22, const BoutReal g_33, + const BoutReal g_12, const BoutReal g_13, const BoutReal g_23, + Mesh* mesh) + : MetricTensor(g_11, g_22, g_33, g_12, g_13, g_23, mesh){}; +}; + +#endif //BOUT_METRIC_TENSOR_HXX diff --git a/include/bout/parallel_boundary_op.hxx b/include/bout/parallel_boundary_op.hxx index d8620e892b..97b3d9a500 100644 --- a/include/bout/parallel_boundary_op.hxx +++ b/include/bout/parallel_boundary_op.hxx @@ -93,7 +93,7 @@ public: void apply(Field3D& f, BoutReal t) override { f.ynext(bndry->dir).allocate(); // Ensure unique before modifying - auto dy = f.getCoordinates()->dy; + auto dy = f.getCoordinates()->dy(); for (bndry->first(); !bndry->isDone(); bndry->next()) { BoutReal value = getValue(*bndry, t); diff --git a/include/bout/physicsmodel.hxx b/include/bout/physicsmodel.hxx index 9fa25d8b0f..2b2badf0f3 100644 --- a/include/bout/physicsmodel.hxx +++ b/include/bout/physicsmodel.hxx @@ -78,6 +78,10 @@ public: add(&value, name, false); } template + void addOnce(const T& value, const std::string& name) { + add(&value, name, false); + } + template void add(T& value, const std::string& name, bool save_repeat = false) { add(&value, name, save_repeat); } diff --git a/manual/sphinx/developer_docs/mesh.rst b/manual/sphinx/developer_docs/mesh.rst index ff3e40d4b0..60ce2643c7 100644 --- a/manual/sphinx/developer_docs/mesh.rst +++ b/manual/sphinx/developer_docs/mesh.rst @@ -278,9 +278,6 @@ metric tensor components are public members of `Coordinates`:: // Covariant metric tensor FieldMetric g_11, g_22, g_33, g_12, g_13, g_23; - int calcCovariant(); // Invert contravatiant metric to get covariant - int calcContravariant(); // Invert covariant metric to get contravariant - If only one of these sets is modified by an external code, then `Coordinates::calcCovariant()` and `Coordinates::calcContravariant()` can be used to calculate the other (uses Gauss-Jordan currently). @@ -292,8 +289,6 @@ other useful quantities:: FieldMetric J; // Jacobian FieldMetric Bxy; // Magnitude of B = nabla z times nabla x - /// Calculate differential geometry quantities from the metric tensor - int geometry(); // Christoffel symbol of the second kind (connection coefficients) FieldMetric G1_11, G1_22, G1_33, G1_12, G1_13; diff --git a/manual/sphinx/developer_docs/petsc_interface.rst b/manual/sphinx/developer_docs/petsc_interface.rst index 9dba044c9b..d9805f9c6b 100644 --- a/manual/sphinx/developer_docs/petsc_interface.rst +++ b/manual/sphinx/developer_docs/petsc_interface.rst @@ -286,8 +286,8 @@ the Laplace operator defined in :ref:`sec-operator-stencil`. :: PetscMatrix matrix(indexer); - Field2D &dx = localmesh->getCoordinates()->dx, - &dy = localmesh->getCoordinates()->dy; + Field2D &dx = localmesh->getCoordinates()->dx(), + &dy = localmesh->getCoordinates()->dy(); // Set up x-derivatives BOUT_FOR(i, indexer->getRegionNobndry()) { diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 7eda5d0266..ee3b469bfb 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -720,7 +720,7 @@ void shiftZ(Field3D& var, int jx, int jy, double zangle) { rfft(&(var(jx, jy, 0)), ncz, v.begin()); // Forward FFT - BoutReal zlength = var.getCoordinates()->zlength()(jx, jy); + BoutReal zlength = var.getCoordinates()->zlength(jx, jy); // Apply phase shift for (int jz = 1; jz <= ncz / 2; jz++) { diff --git a/src/field/vecops.cxx b/src/field/vecops.cxx index 5f34e2af02..fb6b12ce4a 100644 --- a/src/field/vecops.cxx +++ b/src/field/vecops.cxx @@ -106,10 +106,10 @@ Vector3D Grad_perp(const Field3D& f, CELL_LOC outloc, const std::string& method) Vector3D result(f.getMesh()); result.x = DDX(f, outloc, method) - - metric->g_12 * DDY(f, outloc, method) / SQ(metric->J * metric->Bxy); + - metric->g_12() * DDY(f, outloc, method) / SQ(metric->J() * metric->Bxy()); result.y = 0.0; result.z = DDZ(f, outloc, method) - - metric->g_23 * DDY(f, outloc, method) / SQ(metric->J * metric->Bxy); + - metric->g_23() * DDY(f, outloc, method) / SQ(metric->J() * metric->Bxy()); result.setLocation(result.x.getLocation()); @@ -128,9 +128,9 @@ Vector2D Grad_perp(const Field2D& f, CELL_LOC outloc, const std::string& method) Vector2D result(f.getMesh()); result.x = DDX(f, outloc, method) - - metric->g_12 * DDY(f, outloc, method) / SQ(metric->J * metric->Bxy); + - metric->g_12() * DDY(f, outloc, method) / SQ(metric->J() * metric->Bxy()); result.y = 0.0; - result.z = -metric->g_23 * DDY(f, outloc, method) / SQ(metric->J * metric->Bxy); + result.z = -metric->g_23() * DDY(f, outloc, method) / SQ(metric->J() * metric->Bxy()); result.setLocation(result.x.getLocation()); @@ -161,10 +161,10 @@ Coordinates::FieldMetric Div(const Vector2D& v, CELL_LOC outloc, Vector2D vcn = v; vcn.toContravariant(); - Coordinates::FieldMetric result = DDX(metric->J * vcn.x, outloc, method); - result += DDY(metric->J * vcn.y, outloc, method); - result += DDZ(metric->J * vcn.z, outloc, method); - result /= metric->J; + Coordinates::FieldMetric result = DDX(metric->J() * vcn.x, outloc, method); + result += DDY(metric->J() * vcn.y, outloc, method); + result += DDZ(metric->J() * vcn.z, outloc, method); + result /= metric->J(); return result; } @@ -187,7 +187,7 @@ Field3D Div(const Vector3D& v, CELL_LOC outloc, const std::string& method) { Vector3D vcn = v; vcn.toContravariant(); - auto vcnJy = vcn.y.getCoordinates()->J * vcn.y; + auto vcnJy = vcn.y.getCoordinates()->J() * vcn.y; if (v.y.hasParallelSlices()) { // If v.y has parallel slices then we are using ShiftedMetric (with // mesh:calcParallelSlices_on_communicate=true) or FCI, so we should calculate @@ -196,9 +196,9 @@ Field3D Div(const Vector3D& v, CELL_LOC outloc, const std::string& method) { } auto result = DDY(vcnJy, outloc, method); - result += DDX(vcn.x.getCoordinates()->J * vcn.x, outloc, method); - result += DDZ(vcn.z.getCoordinates()->J * vcn.z, outloc, method); - result /= metric->J; + result += DDX(vcn.x.getCoordinates()->J() * vcn.x, outloc, method); + result += DDZ(vcn.z.getCoordinates()->J() * vcn.z, outloc, method); + result /= metric->J(); return result; } @@ -226,10 +226,10 @@ Coordinates::FieldMetric Div(const Vector2D& v, const Field2D& f, CELL_LOC outlo vcn.toContravariant(); Coordinates::FieldMetric result = - FDDX(vcn.x.getCoordinates()->J * vcn.x, f, outloc, method); - result += FDDY(vcn.y.getCoordinates()->J * vcn.y, f, outloc, method); - result += FDDZ(vcn.z.getCoordinates()->J * vcn.z, f, outloc, method); - result /= metric->J; + FDDX(vcn.x.getCoordinates()->J() * vcn.x, f, outloc, method); + result += FDDY(vcn.y.getCoordinates()->J() * vcn.y, f, outloc, method); + result += FDDZ(vcn.z.getCoordinates()->J() * vcn.z, f, outloc, method); + result /= metric->J(); return result; } @@ -251,10 +251,10 @@ Field3D Div(const Vector3D& v, const Field3D& f, CELL_LOC outloc, Vector3D vcn = v; vcn.toContravariant(); - Field3D result = FDDX(vcn.x.getCoordinates()->J * vcn.x, f, outloc, method); - result += FDDY(vcn.y.getCoordinates()->J * vcn.y, f, outloc, method); - result += FDDZ(vcn.z.getCoordinates()->J * vcn.z, f, outloc, method); - result /= metric->J; + Field3D result = FDDX(vcn.x.getCoordinates()->J() * vcn.x, f, outloc, method); + result += FDDY(vcn.y.getCoordinates()->J() * vcn.y, f, outloc, method); + result += FDDZ(vcn.z.getCoordinates()->J() * vcn.z, f, outloc, method); + result /= metric->J(); return result; } @@ -277,12 +277,12 @@ Vector2D Curl(const Vector2D& v) { // get components (curl(v))^j Vector2D result(localmesh); - result.x = (DDY(vco.z) - DDZ(vco.y)) / metric->J; - result.y = (DDZ(vco.x) - DDX(vco.z)) / metric->J; - result.z = (DDX(vco.y) - DDY(vco.x)) / metric->J; + result.x = (DDY(vco.z) - DDZ(vco.y)) / metric->J(); + result.y = (DDZ(vco.x) - DDX(vco.z)) / metric->J(); + result.z = (DDX(vco.y) - DDY(vco.x)) / metric->J(); /// Coordinate torsion - result.z -= metric->ShiftTorsion * vco.z / metric->J; + result.z -= metric->ShiftTorsion() * vco.z / metric->J(); result.setLocation(v.getLocation()); @@ -305,12 +305,12 @@ Vector3D Curl(const Vector3D& v) { // get components (curl(v))^j Vector3D result(localmesh); - result.x = (DDY(vco.z) - DDZ(vco.y)) / metric->J; - result.y = (DDZ(vco.x) - DDX(vco.z)) / metric->J; - result.z = (DDX(vco.y) - DDY(vco.x)) / metric->J; + result.x = (DDY(vco.z) - DDZ(vco.y)) / metric->J(); + result.y = (DDZ(vco.x) - DDX(vco.z)) / metric->J(); + result.z = (DDX(vco.y) - DDY(vco.x)) / metric->J(); // Coordinate torsion - result.z -= metric->ShiftTorsion * vco.z / metric->J; + result.z -= metric->ShiftTorsion() * vco.z / metric->J(); result.setLocation(v.getLocation()); @@ -390,80 +390,80 @@ R V_dot_Grad(const T& v, const F& a) { result.x = VDDX(vcn.x, a.x) + VDDY(vcn.y, a.x) + VDDZ(vcn.z, a.x); BOUT_FOR(i, result.x.getRegion("RGN_ALL")) { result.x[i] -= vcn.x[i] - * (metric->G1_11[i] * a.x[i] + metric->G2_11[i] * a.y[i] - + metric->G3_11[i] * a.z[i]); + * (metric->G1_11()[i] * a.x[i] + metric->G2_11()[i] * a.y[i] + + metric->G3_11()[i] * a.z[i]); result.x[i] -= vcn.y[i] - * (metric->G1_12[i] * a.x[i] + metric->G2_12[i] * a.y[i] - + metric->G3_12[i] * a.z[i]); + * (metric->G1_12()[i] * a.x[i] + metric->G2_12()[i] * a.y[i] + + metric->G3_12()[i] * a.z[i]); result.x[i] -= vcn.z[i] - * (metric->G1_13[i] * a.x[i] + metric->G2_13[i] * a.y[i] - + metric->G3_13[i] * a.z[i]); + * (metric->G1_13()[i] * a.x[i] + metric->G2_13()[i] * a.y[i] + + metric->G3_13()[i] * a.z[i]); } result.y = VDDX(vcn.x, a.y) + VDDY(vcn.y, a.y) + VDDZ(vcn.z, a.y); BOUT_FOR(i, result.y.getRegion("RGN_ALL")) { result.y[i] -= vcn.x[i] - * (metric->G1_12[i] * a.x[i] + metric->G2_12[i] * a.y[i] - + metric->G3_12[i] * a.z[i]); + * (metric->G1_12()[i] * a.x[i] + metric->G2_12()[i] * a.y[i] + + metric->G3_12()[i] * a.z[i]); result.y[i] -= vcn.y[i] - * (metric->G1_22[i] * a.x[i] + metric->G2_22[i] * a.y[i] - + metric->G3_22[i] * a.z[i]); + * (metric->G1_22()[i] * a.x[i] + metric->G2_22()[i] * a.y[i] + + metric->G3_22()[i] * a.z[i]); result.y[i] -= vcn.z[i] - * (metric->G1_23[i] * a.x[i] + metric->G2_23[i] * a.y[i] - + metric->G3_23[i] * a.z[i]); + * (metric->G1_23()[i] * a.x[i] + metric->G2_23()[i] * a.y[i] + + metric->G3_23()[i] * a.z[i]); } result.z = VDDX(vcn.x, a.z) + VDDY(vcn.y, a.z) + VDDZ(vcn.z, a.z); BOUT_FOR(i, result.z.getRegion("RGN_ALL")) { result.z[i] -= vcn.x[i] - * (metric->G1_13[i] * a.x[i] + metric->G2_13[i] * a.y[i] - + metric->G3_13[i] * a.z[i]); + * (metric->G1_13()[i] * a.x[i] + metric->G2_13()[i] * a.y[i] + + metric->G3_13()[i] * a.z[i]); result.z[i] -= vcn.y[i] - * (metric->G1_23[i] * a.x[i] + metric->G2_23[i] * a.y[i] - + metric->G3_23[i] * a.z[i]); + * (metric->G1_23()[i] * a.x[i] + metric->G2_23()[i] * a.y[i] + + metric->G3_23()[i] * a.z[i]); result.z[i] -= vcn.z[i] - * (metric->G1_33[i] * a.x[i] + metric->G2_33[i] * a.y[i] - + metric->G3_33[i] * a.z[i]); + * (metric->G1_33()[i] * a.x[i] + metric->G2_33()[i] * a.y[i] + + metric->G3_33()[i] * a.z[i]); } result.covariant = true; } else { result.x = VDDX(vcn.x, a.x) + VDDY(vcn.y, a.x) + VDDZ(vcn.z, a.x); BOUT_FOR(i, result.x.getRegion("RGN_ALL")) { result.x[i] += vcn.x[i] - * (metric->G1_11[i] * a.x[i] + metric->G1_12[i] * a.y[i] - + metric->G1_13[i] * a.z[i]); + * (metric->G1_11()[i] * a.x[i] + metric->G1_12()[i] * a.y[i] + + metric->G1_13()[i] * a.z[i]); result.x[i] += vcn.y[i] - * (metric->G1_12[i] * a.x[i] + metric->G1_22[i] * a.y[i] - + metric->G1_23[i] * a.z[i]); + * (metric->G1_12()[i] * a.x[i] + metric->G1_22()[i] * a.y[i] + + metric->G1_23()[i] * a.z[i]); result.x[i] += vcn.z[i] - * (metric->G1_13[i] * a.x[i] + metric->G1_23[i] * a.y[i] - + metric->G1_33[i] * a.z[i]); + * (metric->G1_13()[i] * a.x[i] + metric->G1_23()[i] * a.y[i] + + metric->G1_33()[i] * a.z[i]); } result.y = VDDX(vcn.x, a.y) + VDDY(vcn.y, a.y) + VDDZ(vcn.z, a.y); BOUT_FOR(i, result.y.getRegion("RGN_ALL")) { result.y[i] += vcn.x[i] - * (metric->G2_11[i] * a.x[i] + metric->G2_12[i] * a.y[i] - + metric->G2_13[i] * a.z[i]); + * (metric->G2_11()[i] * a.x[i] + metric->G2_12()[i] * a.y[i] + + metric->G2_13()[i] * a.z[i]); result.y[i] += vcn.y[i] - * (metric->G2_12[i] * a.x[i] + metric->G2_22[i] * a.y[i] - + metric->G2_23[i] * a.z[i]); + * (metric->G2_12()[i] * a.x[i] + metric->G2_22()[i] * a.y[i] + + metric->G2_23()[i] * a.z[i]); result.y[i] += vcn.z[i] - * (metric->G2_13[i] * a.x[i] + metric->G2_23[i] * a.y[i] - + metric->G2_33[i] * a.z[i]); + * (metric->G2_13()[i] * a.x[i] + metric->G2_23()[i] * a.y[i] + + metric->G2_33()[i] * a.z[i]); } result.z = VDDX(vcn.x, a.z) + VDDY(vcn.y, a.z) + VDDZ(vcn.z, a.z); BOUT_FOR(i, result.z.getRegion("RGN_ALL")) { result.z[i] += vcn.x[i] - * (metric->G3_11[i] * a.x[i] + metric->G3_12[i] * a.y[i] - + metric->G3_13[i] * a.z[i]); + * (metric->G3_11()[i] * a.x[i] + metric->G3_12()[i] * a.y[i] + + metric->G3_13()[i] * a.z[i]); result.z[i] += vcn.y[i] - * (metric->G3_12[i] * a.x[i] + metric->G3_22[i] * a.y[i] - + metric->G3_23[i] * a.z[i]); + * (metric->G3_12()[i] * a.x[i] + metric->G3_22()[i] * a.y[i] + + metric->G3_23()[i] * a.z[i]); result.z[i] += vcn.z[i] - * (metric->G3_13[i] * a.x[i] + metric->G3_23[i] * a.y[i] - + metric->G3_33[i] * a.z[i]); + * (metric->G3_13()[i] * a.x[i] + metric->G3_23()[i] * a.y[i] + + metric->G3_33()[i] * a.z[i]); } result.covariant = false; diff --git a/src/field/vector2d.cxx b/src/field/vector2d.cxx index 74d3a88a22..9f3fa19d8c 100644 --- a/src/field/vector2d.cxx +++ b/src/field/vector2d.cxx @@ -28,8 +28,6 @@ * **************************************************************************/ -#include - #include #include #include @@ -67,10 +65,10 @@ void Vector2D::toCovariant() { Mesh* localmesh = getMesh(); if (location == CELL_VSHIFT) { - Coordinates *metric_x, *metric_y, *metric_z; - metric_x = localmesh->getCoordinates(CELL_XLOW); - metric_y = localmesh->getCoordinates(CELL_YLOW); - metric_z = localmesh->getCoordinates(CELL_ZLOW); + + const auto* metric_x = localmesh->getCoordinates(CELL_XLOW); + const auto* metric_y = localmesh->getCoordinates(CELL_YLOW); + const auto* metric_z = localmesh->getCoordinates(CELL_ZLOW); // Fields at different locations so we need to interpolate // Note : Could reduce peak memory requirement here by just @@ -86,23 +84,28 @@ void Vector2D::toCovariant() { // multiply by g_{ij} BOUT_FOR(i, x.getRegion("RGN_ALL")) { - x[i] = metric_x->g_11[i] * x[i] + metric_x->g_12[i] * y_at_x[i] - + metric_x->g_13[i] * z_at_x[i]; - y[i] = metric_y->g_22[i] * y[i] + metric_y->g_12[i] * x_at_y[i] - + metric_y->g_23[i] * z_at_y[i]; - z[i] = metric_z->g_33[i] * z[i] + metric_z->g_13[i] * x_at_z[i] - + metric_z->g_23[i] * y_at_z[i]; + x[i] = metric_x->g_11()[i] * x[i] + metric_x->g_12()[i] * y_at_x[i] + + metric_x->g_13()[i] * z_at_x[i]; + y[i] = metric_y->g_22()[i] * y[i] + metric_y->g_12()[i] * x_at_y[i] + + metric_y->g_23()[i] * z_at_y[i]; + z[i] = metric_z->g_33()[i] * z[i] + metric_z->g_13()[i] * x_at_z[i] + + metric_z->g_23()[i] * y_at_z[i]; }; } else { - const auto metric = localmesh->getCoordinates(location); + const auto* metric = localmesh->getCoordinates(location); // Need to use temporary arrays to store result - Coordinates::FieldMetric gx{emptyFrom(x)}, gy{emptyFrom(y)}, gz{emptyFrom(z)}; + Coordinates::FieldMetric gx{emptyFrom(x)}; + Coordinates::FieldMetric gy{emptyFrom(y)}; + Coordinates::FieldMetric gz{emptyFrom(z)}; BOUT_FOR(i, x.getRegion("RGN_ALL")) { - gx[i] = metric->g_11[i] * x[i] + metric->g_12[i] * y[i] + metric->g_13[i] * z[i]; - gy[i] = metric->g_22[i] * y[i] + metric->g_12[i] * x[i] + metric->g_23[i] * z[i]; - gz[i] = metric->g_33[i] * z[i] + metric->g_13[i] * x[i] + metric->g_23[i] * y[i]; + gx[i] = metric->g_11()[i] * x[i] + metric->g_12()[i] * y[i] + + metric->g_13()[i] * z[i]; + gy[i] = metric->g_22()[i] * y[i] + metric->g_12()[i] * x[i] + + metric->g_23()[i] * z[i]; + gz[i] = metric->g_33()[i] * z[i] + metric->g_13()[i] * x[i] + + metric->g_23()[i] * y[i]; }; x = gx; @@ -120,15 +123,14 @@ void Vector2D::toContravariant() { Mesh* localmesh = getMesh(); if (location == CELL_VSHIFT) { - Coordinates *metric_x, *metric_y, *metric_z; - metric_x = localmesh->getCoordinates(CELL_XLOW); - metric_y = localmesh->getCoordinates(CELL_YLOW); - metric_z = localmesh->getCoordinates(CELL_ZLOW); + const auto* metric_x = localmesh->getCoordinates(CELL_XLOW); + const auto* metric_y = localmesh->getCoordinates(CELL_YLOW); + const auto* metric_z = localmesh->getCoordinates(CELL_ZLOW); // Fields at different locations so we need to interpolate // Note : Could reduce peak memory requirement here by just - // dealing with the three components seperately. This would + // dealing with the three components separately. This would // require the use of temporary fields to hold the intermediate // result so would likely only reduce memory usage by one field const auto y_at_x = interp_to(y, x.getLocation()); @@ -140,24 +142,29 @@ void Vector2D::toContravariant() { // multiply by g_{ij} BOUT_FOR(i, x.getRegion("RGN_ALL")) { - x[i] = metric_x->g11[i] * x[i] + metric_x->g12[i] * y_at_x[i] - + metric_x->g13[i] * z_at_x[i]; - y[i] = metric_y->g22[i] * y[i] + metric_y->g12[i] * x_at_y[i] - + metric_y->g23[i] * z_at_y[i]; - z[i] = metric_z->g33[i] * z[i] + metric_z->g13[i] * x_at_z[i] - + metric_z->g23[i] * y_at_z[i]; + x[i] = metric_x->g11()[i] * x[i] + metric_x->g12()[i] * y_at_x[i] + + metric_x->g13()[i] * z_at_x[i]; + y[i] = metric_y->g22()[i] * y[i] + metric_y->g12()[i] * x_at_y[i] + + metric_y->g23()[i] * z_at_y[i]; + z[i] = metric_z->g33()[i] * z[i] + metric_z->g13()[i] * x_at_z[i] + + metric_z->g23()[i] * y_at_z[i]; }; } else { - const auto metric = localmesh->getCoordinates(location); + const auto* metric = localmesh->getCoordinates(location); // Need to use temporary arrays to store result - Coordinates::FieldMetric gx{emptyFrom(x)}, gy{emptyFrom(y)}, gz{emptyFrom(z)}; + Coordinates::FieldMetric gx{emptyFrom(x)}; + Coordinates::FieldMetric gy{emptyFrom(y)}; + Coordinates::FieldMetric gz{emptyFrom(z)}; BOUT_FOR(i, x.getRegion("RGN_ALL")) { - gx[i] = metric->g11[i] * x[i] + metric->g12[i] * y[i] + metric->g13[i] * z[i]; - gy[i] = metric->g22[i] * y[i] + metric->g12[i] * x[i] + metric->g23[i] * z[i]; - gz[i] = metric->g33[i] * z[i] + metric->g13[i] * x[i] + metric->g23[i] * y[i]; + gx[i] = + metric->g11()[i] * x[i] + metric->g12()[i] * y[i] + metric->g13()[i] * z[i]; + gy[i] = + metric->g22()[i] * y[i] + metric->g12()[i] * x[i] + metric->g23()[i] * z[i]; + gz[i] = + metric->g33()[i] * z[i] + metric->g13()[i] * x[i] + metric->g23()[i] * y[i]; }; x = gx; @@ -390,18 +397,19 @@ const Coordinates::FieldMetric Vector2D::operator*(const Vector2D& rhs) const { if (covariant) { // Both covariant - result = - x * rhs.x * metric->g11 + y * rhs.y * metric->g22 + z * rhs.z * metric->g33; - result += (x * rhs.y + y * rhs.x) * metric->g12 - + (x * rhs.z + z * rhs.x) * metric->g13 - + (y * rhs.z + z * rhs.y) * metric->g23; + + result = x * rhs.x * metric->g11() + y * rhs.y * metric->g22() + + z * rhs.z * metric->g33(); + result += (x * rhs.y + y * rhs.x) * metric->g12() + + (x * rhs.z + z * rhs.x) * metric->g13() + + (y * rhs.z + z * rhs.y) * metric->g23(); } else { // Both contravariant - result = - x * rhs.x * metric->g_11 + y * rhs.y * metric->g_22 + z * rhs.z * metric->g_33; - result += (x * rhs.y + y * rhs.x) * metric->g_12 - + (x * rhs.z + z * rhs.x) * metric->g_13 - + (y * rhs.z + z * rhs.y) * metric->g_23; + result = x * rhs.x * metric->g_11() + y * rhs.y * metric->g_22() + + z * rhs.z * metric->g_33(); + result += (x * rhs.y + y * rhs.x) * metric->g_12() + + (x * rhs.z + z * rhs.x) * metric->g_13() + + (y * rhs.z + z * rhs.y) * metric->g_23(); } } diff --git a/src/field/vector3d.cxx b/src/field/vector3d.cxx index 56124595b3..a1a181854d 100644 --- a/src/field/vector3d.cxx +++ b/src/field/vector3d.cxx @@ -28,8 +28,6 @@ * **************************************************************************/ -#include - #include #include #include @@ -87,12 +85,12 @@ void Vector3D::toCovariant() { // multiply by g_{ij} BOUT_FOR(i, localmesh->getRegion3D("RGN_ALL")) { - x[i] = metric_x->g_11[i] * x[i] + metric_x->g_12[i] * y_at_x[i] - + metric_x->g_13[i] * z_at_x[i]; - y[i] = metric_y->g_22[i] * y[i] + metric_y->g_12[i] * x_at_y[i] - + metric_y->g_23[i] * z_at_y[i]; - z[i] = metric_z->g_33[i] * z[i] + metric_z->g_13[i] * x_at_z[i] - + metric_z->g_23[i] * y_at_z[i]; + x[i] = metric_x->g_11()[i] * x[i] + metric_x->g_12()[i] * y_at_x[i] + + metric_x->g_13()[i] * z_at_x[i]; + y[i] = metric_y->g_22()[i] * y[i] + metric_y->g_12()[i] * x_at_y[i] + + metric_y->g_23()[i] * z_at_y[i]; + z[i] = metric_z->g_33()[i] * z[i] + metric_z->g_13()[i] * x_at_z[i] + + metric_z->g_23()[i] * y_at_z[i]; }; } else { const auto metric = localmesh->getCoordinates(location); @@ -101,9 +99,12 @@ void Vector3D::toCovariant() { Field3D gx{emptyFrom(x)}, gy{emptyFrom(y)}, gz{emptyFrom(z)}; BOUT_FOR(i, localmesh->getRegion3D("RGN_ALL")) { - gx[i] = metric->g_11[i] * x[i] + metric->g_12[i] * y[i] + metric->g_13[i] * z[i]; - gy[i] = metric->g_22[i] * y[i] + metric->g_12[i] * x[i] + metric->g_23[i] * z[i]; - gz[i] = metric->g_33[i] * z[i] + metric->g_13[i] * x[i] + metric->g_23[i] * y[i]; + gx[i] = metric->g_11()[i] * x[i] + metric->g_12()[i] * y[i] + + metric->g_13()[i] * z[i]; + gy[i] = metric->g_22()[i] * y[i] + metric->g_12()[i] * x[i] + + metric->g_23()[i] * z[i]; + gz[i] = metric->g_33()[i] * z[i] + metric->g_13()[i] * x[i] + + metric->g_23()[i] * y[i]; }; x = gx; @@ -121,15 +122,14 @@ void Vector3D::toContravariant() { Mesh* localmesh = getMesh(); if (location == CELL_VSHIFT) { - Coordinates *metric_x, *metric_y, *metric_z; - metric_x = localmesh->getCoordinates(CELL_XLOW); - metric_y = localmesh->getCoordinates(CELL_YLOW); - metric_z = localmesh->getCoordinates(CELL_ZLOW); + const auto* metric_x = localmesh->getCoordinates(CELL_XLOW); + const auto* metric_y = localmesh->getCoordinates(CELL_YLOW); + const auto* metric_z = localmesh->getCoordinates(CELL_ZLOW); // Fields at different locations so we need to interpolate // Note : Could reduce peak memory requirement here by just - // dealing with the three components seperately. This would + // dealing with the three components separately. This would // require the use of temporary fields to hold the intermediate // result so would likely only reduce memory usage by one field const auto y_at_x = interp_to(y, x.getLocation()); @@ -140,25 +140,30 @@ void Vector3D::toContravariant() { const auto y_at_z = interp_to(y, z.getLocation()); // multiply by g_{ij} - BOUT_FOR(i, localmesh->getRegion3D("RGN_ALL")) { - x[i] = metric_x->g11[i] * x[i] + metric_x->g12[i] * y_at_x[i] - + metric_x->g13[i] * z_at_x[i]; - y[i] = metric_y->g22[i] * y[i] + metric_y->g12[i] * x_at_y[i] - + metric_y->g23[i] * z_at_y[i]; - z[i] = metric_z->g33[i] * z[i] + metric_z->g13[i] * x_at_z[i] - + metric_z->g23[i] * y_at_z[i]; + BOUT_FOR(i, x.getRegion("RGN_ALL")) { + x[i] = metric_x->g11()[i] * x[i] + metric_x->g12()[i] * y_at_x[i] + + metric_x->g13()[i] * z_at_x[i]; + y[i] = metric_y->g22()[i] * y[i] + metric_y->g12()[i] * x_at_y[i] + + metric_y->g23()[i] * z_at_y[i]; + z[i] = metric_z->g33()[i] * z[i] + metric_z->g13()[i] * x_at_z[i] + + metric_z->g23()[i] * y_at_z[i]; }; } else { - const auto metric = localmesh->getCoordinates(location); + const auto* metric = localmesh->getCoordinates(location); // Need to use temporary arrays to store result - Field3D gx{emptyFrom(x)}, gy{emptyFrom(y)}, gz{emptyFrom(z)}; + Field3D gx{emptyFrom(x)}; + Field3D gy{emptyFrom(y)}; + Field3D gz{emptyFrom(z)}; BOUT_FOR(i, localmesh->getRegion3D("RGN_ALL")) { - gx[i] = metric->g11[i] * x[i] + metric->g12[i] * y[i] + metric->g13[i] * z[i]; - gy[i] = metric->g22[i] * y[i] + metric->g12[i] * x[i] + metric->g23[i] * z[i]; - gz[i] = metric->g33[i] * z[i] + metric->g13[i] * x[i] + metric->g23[i] * y[i]; + gx[i] = + metric->g11()[i] * x[i] + metric->g12()[i] * y[i] + metric->g13()[i] * z[i]; + gy[i] = + metric->g22()[i] * y[i] + metric->g12()[i] * x[i] + metric->g23()[i] * z[i]; + gz[i] = + metric->g33()[i] * z[i] + metric->g13()[i] * x[i] + metric->g23()[i] * y[i]; }; x = gx; @@ -379,9 +384,9 @@ Vector3D& Vector3D::operator/=(const Field3D& rhs) { Coordinates* metric = localmesh->getCoordinates(lhs.getLocation()); \ \ /* calculate contravariant components of cross-product */ \ - result.x = (lco.y * rco.z - lco.z * rco.y) / metric->J; \ - result.y = (lco.z * rco.x - lco.x * rco.z) / metric->J; \ - result.z = (lco.x * rco.y - lco.y * rco.x) / metric->J; \ + result.x = (lco.y * rco.z - lco.z * rco.y) / metric->J(); \ + result.y = (lco.z * rco.x - lco.x * rco.z) / metric->J(); \ + result.z = (lco.x * rco.y - lco.y * rco.x) / metric->J(); \ result.covariant = false; \ \ return result; \ @@ -470,7 +475,7 @@ const Field3D Vector3D::operator*(const Vector3D& rhs) const { Mesh* mesh = getMesh(); Field3D result{emptyFrom(x)}; - ASSERT2(location == rhs.getLocation()) + ASSERT2(location == rhs.getLocation()); if (rhs.covariant ^ covariant) { // Both different - just multiply components @@ -482,18 +487,18 @@ const Field3D Vector3D::operator*(const Vector3D& rhs) const { if (covariant) { // Both covariant - result = - x * rhs.x * metric->g11 + y * rhs.y * metric->g22 + z * rhs.z * metric->g33; - result += (x * rhs.y + y * rhs.x) * metric->g12 - + (x * rhs.z + z * rhs.x) * metric->g13 - + (y * rhs.z + z * rhs.y) * metric->g23; + result = x * rhs.x * metric->g11() + y * rhs.y * metric->g22() + + z * rhs.z * metric->g33(); + result += (x * rhs.y + y * rhs.x) * metric->g12() + + (x * rhs.z + z * rhs.x) * metric->g13() + + (y * rhs.z + z * rhs.y) * metric->g23(); } else { // Both contravariant - result = - x * rhs.x * metric->g_11 + y * rhs.y * metric->g_22 + z * rhs.z * metric->g_33; - result += (x * rhs.y + y * rhs.x) * metric->g_12 - + (x * rhs.z + z * rhs.x) * metric->g_13 - + (y * rhs.z + z * rhs.y) * metric->g_23; + result = x * rhs.x * metric->g_11() + y * rhs.y * metric->g_22() + + z * rhs.z * metric->g_33(); + result += (x * rhs.y + y * rhs.x) * metric->g_12() + + (x * rhs.z + z * rhs.x) * metric->g_13() + + (y * rhs.z + z * rhs.y) * metric->g_23(); } } @@ -514,18 +519,18 @@ const Field3D Vector3D::operator*(const Vector2D& rhs) const { Coordinates* metric = x.getCoordinates(location); if (covariant) { // Both covariant - result = - x * rhs.x * metric->g11 + y * rhs.y * metric->g22 + z * rhs.z * metric->g33; - result += (x * rhs.y + y * rhs.x) * metric->g12 - + (x * rhs.z + z * rhs.x) * metric->g13 - + (y * rhs.z + z * rhs.y) * metric->g23; + result = x * rhs.x * metric->g11() + y * rhs.y * metric->g22() + + z * rhs.z * metric->g33(); + result += (x * rhs.y + y * rhs.x) * metric->g12() + + (x * rhs.z + z * rhs.x) * metric->g13() + + (y * rhs.z + z * rhs.y) * metric->g23(); } else { // Both contravariant - result = - x * rhs.x * metric->g_11 + y * rhs.y * metric->g_22 + z * rhs.z * metric->g_33; - result += (x * rhs.y + y * rhs.x) * metric->g_12 - + (x * rhs.z + z * rhs.x) * metric->g_13 - + (y * rhs.z + z * rhs.y) * metric->g_23; + result = x * rhs.x * metric->g_11() + y * rhs.y * metric->g_22() + + z * rhs.z * metric->g_33(); + result += (x * rhs.y + y * rhs.x) * metric->g_12() + + (x * rhs.z + z * rhs.x) * metric->g_13() + + (y * rhs.z + z * rhs.y) * metric->g_23(); } } diff --git a/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx b/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx index 5ce4e540b7..12626a4cdb 100644 --- a/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx +++ b/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx @@ -162,7 +162,7 @@ FieldPerp LaplaceCyclic::solve(const FieldPerp& rhs, const FieldPerp& x0) { // Get elements of the tridiagonal matrix // including boundary conditions - BoutReal zlen = getUniform(coords->dz) * (localmesh->LocalNz - 3); + BoutReal zlen = getUniform(coords->dz()) * (localmesh->LocalNz - 3); BOUT_OMP_PERF(for nowait) for (int kz = 0; kz < nmode; kz++) { // wave number is 1/[rad]; DST has extra 2. @@ -394,7 +394,7 @@ Field3D LaplaceCyclic::solve(const Field3D& rhs, const Field3D& x0) { // Get elements of the tridiagonal matrix // including boundary conditions - const BoutReal zlen = getUniform(coords->dz) * (localmesh->LocalNz - 3); + const BoutReal zlen = getUniform(coords->dz()) * (localmesh->LocalNz - 3); BOUT_OMP_PERF(for nowait) for (int ind = 0; ind < nsys; ind++) { // ind = (iy - ys) * nmode + kz diff --git a/src/invert/laplace/impls/hypre3d/hypre3d_laplace.cxx b/src/invert/laplace/impls/hypre3d/hypre3d_laplace.cxx index d789e5e408..24448da5e3 100644 --- a/src/invert/laplace/impls/hypre3d/hypre3d_laplace.cxx +++ b/src/invert/laplace/impls/hypre3d/hypre3d_laplace.cxx @@ -101,8 +101,8 @@ LaplaceHypre3d::LaplaceHypre3d(Options* opt, const CELL_LOC loc, Mesh* mesh_in, BOUT_FOR_SERIAL(i, indexer->getRegionInnerX()) { if (isInnerBoundaryFlagSet(INVERT_AC_GRAD)) { // Neumann on inner X boundary - operator3D(i, i) = -1. / coords->dx[i] / sqrt(coords->g_11[i]); - operator3D(i, i.xp()) = 1. / coords->dx[i] / sqrt(coords->g_11[i]); + operator3D(i, i) = -1. / coords->dx()[i] / sqrt(coords->g_11()[i]); + operator3D(i, i.xp()) = 1. / coords->dx()[i] / sqrt(coords->g_11()[i]); } else { // Dirichlet on inner X boundary operator3D(i, i) = 0.5; @@ -113,8 +113,8 @@ LaplaceHypre3d::LaplaceHypre3d(Options* opt, const CELL_LOC loc, Mesh* mesh_in, BOUT_FOR_SERIAL(i, indexer->getRegionOuterX()) { if (isOuterBoundaryFlagSet(INVERT_AC_GRAD)) { // Neumann on outer X boundary - operator3D(i, i) = 1. / coords->dx[i] / sqrt(coords->g_11[i]); - operator3D(i, i.xm()) = -1. / coords->dx[i] / sqrt(coords->g_11[i]); + operator3D(i, i) = 1. / coords->dx()[i] / sqrt(coords->g_11()[i]); + operator3D(i, i.xm()) = -1. / coords->dx()[i] / sqrt(coords->g_11()[i]); } else { // Dirichlet on outer X boundary operator3D(i, i) = 0.5; @@ -125,8 +125,8 @@ LaplaceHypre3d::LaplaceHypre3d(Options* opt, const CELL_LOC loc, Mesh* mesh_in, BOUT_FOR_SERIAL(i, indexer->getRegionLowerY()) { if (lower_boundary_flags & INVERT_AC_GRAD) { // Neumann on lower Y boundary - operator3D(i, i) = -1. / coords->dy[i] / sqrt(coords->g_22[i]); - operator3D(i, i.yp()) = 1. / coords->dy[i] / sqrt(coords->g_22[i]); + operator3D(i, i) = -1. / coords->dy()[i] / sqrt(coords->g_22()[i]); + operator3D(i, i.yp()) = 1. / coords->dy()[i] / sqrt(coords->g_22()[i]); } else { // Dirichlet on lower Y boundary operator3D(i, i) = 0.5; @@ -137,8 +137,8 @@ LaplaceHypre3d::LaplaceHypre3d(Options* opt, const CELL_LOC loc, Mesh* mesh_in, BOUT_FOR_SERIAL(i, indexer->getRegionUpperY()) { if (upper_boundary_flags & INVERT_AC_GRAD) { // Neumann on upper Y boundary - operator3D(i, i) = 1. / coords->dy[i] / sqrt(coords->g_22[i]); - operator3D(i, i.ym()) = -1. / coords->dy[i] / sqrt(coords->g_22[i]); + operator3D(i, i) = 1. / coords->dy()[i] / sqrt(coords->g_22()[i]); + operator3D(i, i.ym()) = -1. / coords->dy()[i] / sqrt(coords->g_22()[i]); } else { // Dirichlet on upper Y boundary operator3D(i, i) = 0.5; @@ -277,7 +277,7 @@ void LaplaceHypre3d::updateMatrix3D() { const Field3D dc_dx = issetC ? DDX(C2) : Field3D(); const Field3D dc_dy = issetC ? DDY(C2) : Field3D(); const Field3D dc_dz = issetC ? DDZ(C2) : Field3D(); - const Field2D dJ_dy = DDY(coords->J / coords->g_22); + const Field3D dJ_dy = DDY(coords->J() / coords->g_22()); // Set up the matrix for the internal points on the grid. // Boundary conditions were set in the constructor. @@ -286,17 +286,17 @@ void LaplaceHypre3d::updateMatrix3D() { // avoid confusing it with the x-index. // Calculate coefficients for the terms in the differential operator - BoutReal C_df_dx = coords->G1[l], C_df_dz = coords->G3[l]; + BoutReal C_df_dx = coords->G1()[l], C_df_dz = coords->G3()[l]; if (issetD) { C_df_dx *= D[l]; C_df_dz *= D[l]; } if (issetC) { - C_df_dx += (coords->g11[l] * dc_dx[l] + coords->g12[l] * dc_dy[l] - + coords->g13[l] * dc_dz[l]) + C_df_dx += (coords->g11()[l] * dc_dx[l] + coords->g12()[l] * dc_dy[l] + + coords->g13()[l] * dc_dz[l]) / C1[l]; - C_df_dz += (coords->g13[l] * dc_dx[l] + coords->g23[l] * dc_dy[l] - + coords->g33[l] * dc_dz[l]) + C_df_dz += (coords->g13()[l] * dc_dx[l] + coords->g23()[l] * dc_dy[l] + + coords->g33()[l] * dc_dz[l]) / C1[l]; } if (issetE) { @@ -304,32 +304,32 @@ void LaplaceHypre3d::updateMatrix3D() { C_df_dz += Ez[l]; } - BoutReal C_d2f_dx2 = coords->g11[l], - C_d2f_dy2 = (coords->g22[l] - 1.0 / coords->g_22[l]), - C_d2f_dz2 = coords->g33[l]; + BoutReal C_d2f_dx2 = coords->g11()[l], + C_d2f_dy2 = (coords->g22()[l] - 1.0 / coords->g_22()[l]), + C_d2f_dz2 = coords->g33()[l]; if (issetD) { C_d2f_dx2 *= D[l]; C_d2f_dy2 *= D[l]; C_d2f_dz2 *= D[l]; } - BoutReal C_d2f_dxdz = 2 * coords->g13[l]; + BoutReal C_d2f_dxdz = 2 * coords->g13()[l]; if (issetD) { C_d2f_dxdz *= D[l]; } // Adjust the coefficients to include finite-difference factors if (nonuniform) { - C_df_dx += C_d2f_dx2 * coords->d1_dx[l]; + C_df_dx += C_d2f_dx2 * coords->d1_dx()[l]; } - C_df_dx /= 2 * coords->dx[l]; - C_df_dz /= 2 * coords->dz[l]; + C_df_dx /= 2 * coords->dx()[l]; + C_df_dz /= 2 * coords->dz()[l]; - C_d2f_dx2 /= SQ(coords->dx[l]); - C_d2f_dy2 /= SQ(coords->dy[l]); - C_d2f_dz2 /= SQ(coords->dz[l]); + C_d2f_dx2 /= SQ(coords->dx()[l]); + C_d2f_dy2 /= SQ(coords->dy()[l]); + C_d2f_dz2 /= SQ(coords->dz()[l]); - C_d2f_dxdz /= 4 * coords->dx[l] * coords->dz[l]; + C_d2f_dxdz /= 4 * coords->dx()[l] * coords->dz()[l]; operator3D(l, l) = -2 * (C_d2f_dx2 + C_d2f_dy2 + C_d2f_dz2) + A[l]; operator3D(l, l.xp()) = C_df_dx + C_d2f_dx2; @@ -360,23 +360,23 @@ void LaplaceHypre3d::updateMatrix3D() { // Must add these (rather than assign) so that elements used in // interpolation don't overwrite each other. BOUT_FOR_SERIAL(l, indexer->getRegionNobndry()) { - BoutReal C_df_dy = (coords->G2[l] - dJ_dy[l] / coords->J[l]); + BoutReal C_df_dy = (coords->G2()[l] - dJ_dy[l] / coords->J()[l]); if (issetD) { C_df_dy *= D[l]; } if (issetC) { - C_df_dy += - (coords->g12[l] * dc_dx[l] + (coords->g22[l] - 1. / coords->g_22[l]) * dc_dy[l] - + coords->g23[l] * dc_dz[l]) - / C1[l]; + C_df_dy += (coords->g12()[l] * dc_dx[l] + + (coords->g22()[l] - 1. / coords->g_22()[l]) * dc_dy[l] + + coords->g23()[l] * dc_dz[l]) + / C1[l]; } - BoutReal C_d2f_dy2 = (coords->g22[l] - 1.0 / coords->g_22[l]); + BoutReal C_d2f_dy2 = (coords->g22()[l] - 1.0 / coords->g_22()[l]); if (issetD) { C_d2f_dy2 *= D[l]; } - BoutReal C_d2f_dxdy = 2 * coords->g12[l], C_d2f_dydz = 2 * coords->g23[l]; + BoutReal C_d2f_dxdy = 2 * coords->g12()[l], C_d2f_dydz = 2 * coords->g23()[l]; if (issetD) { C_d2f_dxdy *= D[l]; C_d2f_dydz *= D[l]; @@ -384,14 +384,14 @@ void LaplaceHypre3d::updateMatrix3D() { // Adjust the coefficients to include finite-difference factors if (nonuniform) { - C_df_dy += C_d2f_dy2 * coords->d1_dy[l]; + C_df_dy += C_d2f_dy2 * coords->d1_dy()[l]; } - C_df_dy /= 2 * coords->dy[l]; - C_d2f_dy2 /= SQ(coords->dy[l]); - C_d2f_dxdy /= 4 * coords->dx[l]; // NOTE: This value is not completed here. It needs - // to be divide by dx(i +/- 1, j, k) when using to - // set a matrix element - C_d2f_dydz /= 4 * coords->dy[l] * coords->dz[l]; + C_df_dy /= 2 * coords->dy()[l]; + C_d2f_dy2 /= SQ(coords->dy()[l]); + C_d2f_dxdy /= 4 * coords->dx()[l]; // NOTE: This value is not completed here. It needs + // to be divide by dx(i +/- 1, j, k) when using to + // set a matrix element + C_d2f_dydz /= 4 * coords->dy()[l] * coords->dz()[l]; // The values stored in the y-boundary are already interpolated // up/down, so we don't want the matrix to do any such @@ -401,10 +401,10 @@ void LaplaceHypre3d::updateMatrix3D() { operator3D.yup(yup)(l, l.yp()) += C_df_dy + C_d2f_dy2; operator3D.ydown(ydown)(l, l.ym()) += -C_df_dy + C_d2f_dy2; - operator3D.yup(yup)(l, l.xp().yp()) += C_d2f_dxdy / coords->dy[l.xp()]; - operator3D.ydown(ydown)(l, l.xp().ym()) += -C_d2f_dxdy / coords->dy[l.xp()]; - operator3D.yup(yup)(l, l.xm().yp()) += -C_d2f_dxdy / coords->dy[l.xm()]; - operator3D.ydown(ydown)(l, l.xm().ym()) += C_d2f_dxdy / coords->dy[l.xm()]; + operator3D.yup(yup)(l, l.xp().yp()) += C_d2f_dxdy / coords->dy()[l.xp()]; + operator3D.ydown(ydown)(l, l.xp().ym()) += -C_d2f_dxdy / coords->dy()[l.xp()]; + operator3D.yup(yup)(l, l.xm().yp()) += -C_d2f_dxdy / coords->dy()[l.xm()]; + operator3D.ydown(ydown)(l, l.xm().ym()) += C_d2f_dxdy / coords->dy()[l.xm()]; operator3D.yup(yup)(l, l.yp().zp()) += C_d2f_dydz; operator3D.yup(yup)(l, l.yp().zm()) += -C_d2f_dydz; operator3D.ydown(ydown)(l, l.ym().zp()) += -C_d2f_dydz; diff --git a/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx b/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx index c5076cd499..700c1bc3bd 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx +++ b/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx @@ -619,7 +619,8 @@ void LaplaceMultigrid::generateMatrixF(int level) { + coords->g13(i2, yindex) * ddz_C // (could assume zero, at least initially, if easier; then check this is true in constructor) ) - / coords->dx(i2, yindex); // coefficient of 1st derivative stencil (x-direction) + / coords->dx(i2, + yindex); // coefficient of 1st derivative stencil (x-direction) if (nonuniform) { // add correction for non-uniform dx dxd += D(i2, yindex, k2) * coords->d1_dx(i2, yindex); diff --git a/src/invert/laplace/impls/naulin/naulin_laplace.cxx b/src/invert/laplace/impls/naulin/naulin_laplace.cxx index 7a614c3498..c48a04af68 100644 --- a/src/invert/laplace/impls/naulin/naulin_laplace.cxx +++ b/src/invert/laplace/impls/naulin/naulin_laplace.cxx @@ -254,8 +254,8 @@ Field3D LaplaceNaulin::solve(const Field3D& rhs, const Field3D& x0) { Field3D ddx_x = DDX(x_in, location, "C2"); Field3D ddz_x = DDZ(x_in, location, "FFT"); return rhsOverD - - (coords->g11 * coef_x_AC * ddx_x + coords->g33 * coef_z * ddz_x - + coords->g13 * (coef_x_AC * ddz_x + coef_z * ddx_x)) + - (coords->g11() * coef_x_AC * ddx_x + coords->g33() * coef_z * ddz_x + + coords->g13() * (coef_x_AC * ddz_x + coef_z * ddx_x)) - AOverD_AC * x_in; }; diff --git a/src/invert/laplace/impls/pcr/pcr.cxx b/src/invert/laplace/impls/pcr/pcr.cxx index 48bbdbac4b..6cac74ee92 100644 --- a/src/invert/laplace/impls/pcr/pcr.cxx +++ b/src/invert/laplace/impls/pcr/pcr.cxx @@ -160,7 +160,7 @@ FieldPerp LaplacePCR::solve(const FieldPerp& rhs, const FieldPerp& x0) { } if (dst) { - const BoutReal zlen = getUniform(coords->dz) * (localmesh->LocalNz - 3); + const BoutReal zlen = getUniform(coords->dz()) * (localmesh->LocalNz - 3); BOUT_OMP_PERF(parallel) { /// Create a local thread-scope working array @@ -366,7 +366,7 @@ Field3D LaplacePCR::solve(const Field3D& rhs, const Field3D& x0) { auto bcmplx3D = Matrix(nsys, nx); if (dst) { - const BoutReal zlen = getUniform(coords->dz) * (localmesh->LocalNz - 3); + const BoutReal zlen = getUniform(coords->dz()) * (localmesh->LocalNz - 3); BOUT_OMP_PERF(parallel) { /// Create a local thread-scope working array diff --git a/src/invert/laplace/impls/pcr_thomas/pcr_thomas.cxx b/src/invert/laplace/impls/pcr_thomas/pcr_thomas.cxx index 61c8f58694..50474f9670 100644 --- a/src/invert/laplace/impls/pcr_thomas/pcr_thomas.cxx +++ b/src/invert/laplace/impls/pcr_thomas/pcr_thomas.cxx @@ -156,7 +156,7 @@ FieldPerp LaplacePCR_THOMAS::solve(const FieldPerp& rhs, const FieldPerp& x0) { } if (dst) { - const BoutReal zlength = getUniform(coords->dz) * (localmesh->LocalNz - 3); + const BoutReal zlength = getUniform(coords->dz()) * (localmesh->LocalNz - 3); BOUT_OMP_PERF(parallel) { /// Create a local thread-scope working array @@ -362,7 +362,7 @@ Field3D LaplacePCR_THOMAS::solve(const Field3D& rhs, const Field3D& x0) { auto bcmplx3D = Matrix(nsys, nx); if (dst) { - const BoutReal zlength = getUniform(coords->dz) * (localmesh->LocalNz - 3); + const BoutReal zlength = getUniform(coords->dz()) * (localmesh->LocalNz - 3); BOUT_OMP_PERF(parallel) { /// Create a local thread-scope working array diff --git a/src/invert/laplace/impls/petsc3damg/petsc3damg.cxx b/src/invert/laplace/impls/petsc3damg/petsc3damg.cxx index a7bfd209ee..7f4bcbd4b2 100644 --- a/src/invert/laplace/impls/petsc3damg/petsc3damg.cxx +++ b/src/invert/laplace/impls/petsc3damg/petsc3damg.cxx @@ -120,7 +120,8 @@ LaplacePetsc3dAmg::LaplacePetsc3dAmg(Options* opt, const CELL_LOC loc, Mesh* mes // Set up boundary conditions in operator const bool inner_X_neumann = isInnerBoundaryFlagSet(INVERT_AC_GRAD); - const auto inner_X_BC = inner_X_neumann ? -1. / coords->dx / sqrt(coords->g_11) : 0.5; + const auto inner_X_BC = + inner_X_neumann ? -1. / coords->dx() / sqrt(coords->g_11()) : 0.5; const auto inner_X_BC_plus = inner_X_neumann ? -inner_X_BC : 0.5; BOUT_FOR_SERIAL(i, indexer->getRegionInnerX()) { @@ -129,7 +130,8 @@ LaplacePetsc3dAmg::LaplacePetsc3dAmg(Options* opt, const CELL_LOC loc, Mesh* mes } const bool outer_X_neumann = isOuterBoundaryFlagSet(INVERT_AC_GRAD); - const auto outer_X_BC = outer_X_neumann ? 1. / coords->dx / sqrt(coords->g_11) : 0.5; + const auto outer_X_BC = + outer_X_neumann ? 1. / coords->dx() / sqrt(coords->g_11()) : 0.5; const auto outer_X_BC_minus = outer_X_neumann ? -outer_X_BC : 0.5; BOUT_FOR_SERIAL(i, indexer->getRegionOuterX()) { @@ -138,7 +140,8 @@ LaplacePetsc3dAmg::LaplacePetsc3dAmg(Options* opt, const CELL_LOC loc, Mesh* mes } const bool lower_Y_neumann = flagSet(lower_boundary_flags, INVERT_AC_GRAD); - const auto lower_Y_BC = lower_Y_neumann ? -1. / coords->dy / sqrt(coords->g_22) : 0.5; + const auto lower_Y_BC = + lower_Y_neumann ? -1. / coords->dy() / sqrt(coords->g_22()) : 0.5; const auto lower_Y_BC_plus = lower_Y_neumann ? -lower_Y_BC : 0.5; BOUT_FOR_SERIAL(i, indexer->getRegionLowerY()) { @@ -147,7 +150,8 @@ LaplacePetsc3dAmg::LaplacePetsc3dAmg(Options* opt, const CELL_LOC loc, Mesh* mes } const bool upper_Y_neumann = flagSet(upper_boundary_flags, INVERT_AC_GRAD); - const auto upper_Y_BC = upper_Y_neumann ? 1. / coords->dy / sqrt(coords->g_22) : 0.5; + const auto upper_Y_BC = + upper_Y_neumann ? 1. / coords->dy() / sqrt(coords->g_22()) : 0.5; const auto upper_Y_BC_minus = upper_Y_neumann ? -upper_Y_BC : 0.5; BOUT_FOR_SERIAL(i, indexer->getRegionUpperY()) { @@ -275,7 +279,7 @@ void LaplacePetsc3dAmg::updateMatrix3D() { const Field3D dc_dx = issetC ? DDX(C2) : Field3D(); const Field3D dc_dy = issetC ? DDY(C2) : Field3D(); const Field3D dc_dz = issetC ? DDZ(C2) : Field3D(); - const auto dJ_dy = DDY(coords->J / coords->g_22); + const auto dJ_dy = DDY(coords->J() / coords->g_22()); // Set up the matrix for the internal points on the grid. // Boundary conditions were set in the constructor. @@ -284,18 +288,18 @@ void LaplacePetsc3dAmg::updateMatrix3D() { // avoid confusing it with the x-index. // Calculate coefficients for the terms in the differential operator - BoutReal C_df_dx = coords->G1[l]; - BoutReal C_df_dz = coords->G3[l]; + BoutReal C_df_dx = coords->G1()[l]; + BoutReal C_df_dz = coords->G3()[l]; if (issetD) { C_df_dx *= D[l]; C_df_dz *= D[l]; } if (issetC) { - C_df_dx += (coords->g11[l] * dc_dx[l] + coords->g12[l] * dc_dy[l] - + coords->g13[l] * dc_dz[l]) + C_df_dx += (coords->g11()[l] * dc_dx[l] + coords->g12()[l] * dc_dy[l] + + coords->g13()[l] * dc_dz[l]) / C1[l]; - C_df_dz += (coords->g13[l] * dc_dx[l] + coords->g23[l] * dc_dy[l] - + coords->g33[l] * dc_dz[l]) + C_df_dz += (coords->g13()[l] * dc_dx[l] + coords->g23()[l] * dc_dy[l] + + coords->g33()[l] * dc_dz[l]) / C1[l]; } if (issetE) { @@ -303,32 +307,32 @@ void LaplacePetsc3dAmg::updateMatrix3D() { C_df_dz += Ez[l]; } - BoutReal C_d2f_dx2 = coords->g11[l]; - BoutReal C_d2f_dy2 = (coords->g22[l] - 1.0 / coords->g_22[l]); - BoutReal C_d2f_dz2 = coords->g33[l]; + BoutReal C_d2f_dx2 = coords->g11()[l]; + BoutReal C_d2f_dy2 = (coords->g22()[l] - 1.0 / coords->g_22()[l]); + BoutReal C_d2f_dz2 = coords->g33()[l]; if (issetD) { C_d2f_dx2 *= D[l]; C_d2f_dy2 *= D[l]; C_d2f_dz2 *= D[l]; } - BoutReal C_d2f_dxdz = 2 * coords->g13[l]; + BoutReal C_d2f_dxdz = 2 * coords->g13()[l]; if (issetD) { C_d2f_dxdz *= D[l]; } // Adjust the coefficients to include finite-difference factors if (nonuniform) { - C_df_dx += C_d2f_dx2 * coords->d1_dx[l]; + C_df_dx += C_d2f_dx2 * coords->d1_dx()[l]; } - C_df_dx /= 2 * coords->dx[l]; - C_df_dz /= 2 * coords->dz[l]; + C_df_dx /= 2 * coords->dx()[l]; + C_df_dz /= 2 * coords->dz()[l]; - C_d2f_dx2 /= SQ(coords->dx[l]); - C_d2f_dy2 /= SQ(coords->dy[l]); - C_d2f_dz2 /= SQ(coords->dz[l]); + C_d2f_dx2 /= SQ(coords->dx()[l]); + C_d2f_dy2 /= SQ(coords->dy()[l]); + C_d2f_dz2 /= SQ(coords->dz()[l]); - C_d2f_dxdz /= 4 * coords->dx[l] * coords->dz[l]; + C_d2f_dxdz /= 4 * coords->dx()[l] * coords->dz()[l]; operator3D(l, l) = -2 * (C_d2f_dx2 + C_d2f_dy2 + C_d2f_dz2) + A[l]; operator3D(l, l.xp()) = C_df_dx + C_d2f_dx2; @@ -360,24 +364,24 @@ void LaplacePetsc3dAmg::updateMatrix3D() { // Must add these (rather than assign) so that elements used in // interpolation don't overwrite each other. BOUT_FOR_SERIAL(l, indexer->getRegionNobndry()) { - BoutReal C_df_dy = (coords->G2[l] - dJ_dy[l] / coords->J[l]); + BoutReal C_df_dy = (coords->G2()[l] - dJ_dy[l] / coords->J()[l]); if (issetD) { C_df_dy *= D[l]; } if (issetC) { - C_df_dy += - (coords->g12[l] * dc_dx[l] + (coords->g22[l] - 1. / coords->g_22[l]) * dc_dy[l] - + coords->g23[l] * dc_dz[l]) - / C1[l]; + C_df_dy += (coords->g12()[l] * dc_dx[l] + + (coords->g22()[l] - 1. / coords->g_22()[l]) * dc_dy[l] + + coords->g23()[l] * dc_dz[l]) + / C1[l]; } - BoutReal C_d2f_dy2 = (coords->g22[l] - 1.0 / coords->g_22[l]); + BoutReal C_d2f_dy2 = (coords->g22()[l] - 1.0 / coords->g_22()[l]); if (issetD) { C_d2f_dy2 *= D[l]; } - BoutReal C_d2f_dxdy = 2 * coords->g12[l]; - BoutReal C_d2f_dydz = 2 * coords->g23[l]; + BoutReal C_d2f_dxdy = 2 * coords->g12()[l]; + BoutReal C_d2f_dydz = 2 * coords->g23()[l]; if (issetD) { C_d2f_dxdy *= D[l]; C_d2f_dydz *= D[l]; @@ -385,15 +389,15 @@ void LaplacePetsc3dAmg::updateMatrix3D() { // Adjust the coefficients to include finite-difference factors if (nonuniform) { - C_df_dy += C_d2f_dy2 * coords->d1_dy[l]; + C_df_dy += C_d2f_dy2 * coords->d1_dy()[l]; } - C_df_dy /= 2 * coords->dy[l]; - C_d2f_dy2 /= SQ(coords->dy[l]); + C_df_dy /= 2 * coords->dy()[l]; + C_d2f_dy2 /= SQ(coords->dy()[l]); C_d2f_dxdy /= - 4 * coords->dx[l]; // NOTE: This value is not completed here. It needs to - // be divide by dx(i +/- 1, j, k) when using to set a - // matrix element - C_d2f_dydz /= 4 * coords->dy[l] * coords->dz[l]; + 4 * coords->dx()[l]; // NOTE: This value is not completed here. It needs to + // be divide by dx(i +/- 1, j, k) when using to set a + // matrix element + C_d2f_dydz /= 4 * coords->dy()[l] * coords->dz()[l]; // The values stored in the y-boundary are already interpolated // up/down, so we don't want the matrix to do any such @@ -403,10 +407,10 @@ void LaplacePetsc3dAmg::updateMatrix3D() { operator3D.yup(yup)(l, l.yp()) += C_df_dy + C_d2f_dy2; operator3D.ydown(ydown)(l, l.ym()) += -C_df_dy + C_d2f_dy2; - operator3D.yup(yup)(l, l.xp().yp()) += C_d2f_dxdy / coords->dy[l.xp()]; - operator3D.ydown(ydown)(l, l.xp().ym()) += -C_d2f_dxdy / coords->dy[l.xp()]; - operator3D.yup(yup)(l, l.xm().yp()) += -C_d2f_dxdy / coords->dy[l.xm()]; - operator3D.ydown(ydown)(l, l.xm().ym()) += C_d2f_dxdy / coords->dy[l.xm()]; + operator3D.yup(yup)(l, l.xp().yp()) += C_d2f_dxdy / coords->dy()[l.xp()]; + operator3D.ydown(ydown)(l, l.xp().ym()) += -C_d2f_dxdy / coords->dy()[l.xp()]; + operator3D.yup(yup)(l, l.xm().yp()) += -C_d2f_dxdy / coords->dy()[l.xm()]; + operator3D.ydown(ydown)(l, l.xm().ym()) += C_d2f_dxdy / coords->dy()[l.xm()]; operator3D.yup(yup)(l, l.yp().zp()) += C_d2f_dydz; operator3D.yup(yup)(l, l.yp().zm()) += -C_d2f_dydz; operator3D.ydown(ydown)(l, l.ym().zp()) += -C_d2f_dydz; diff --git a/src/invert/laplace/invert_laplace.cxx b/src/invert/laplace/invert_laplace.cxx index 4032499781..e9008cf4f0 100644 --- a/src/invert/laplace/invert_laplace.cxx +++ b/src/invert/laplace/invert_laplace.cxx @@ -110,7 +110,7 @@ Laplacian::Laplacian(Options* options, const CELL_LOC loc, Mesh* mesh_in, nonuniform = (*options)["nonuniform"] .doc("Use non-uniform grid corrections? Default is the mesh setting.") - .withDefault(coords->non_uniform); + .withDefault(coords->non_uniform()); all_terms = (*options)["all_terms"].doc("Include first derivative terms?").withDefault(true); @@ -269,7 +269,7 @@ void Laplacian::tridagCoefs(int jx, int jy, int jz, dcomplex& a, dcomplex& b, dc ASSERT1(ccoef == nullptr || ccoef->getLocation() == loc); ASSERT1(d == nullptr || d->getLocation() == loc); - BoutReal kwave = jz * 2.0 * PI / coords->zlength()(jx, jy); // wave number is 1/[rad] + BoutReal kwave = jz * 2.0 * PI / coords->zlength(jx, jy); // wave number is 1/[rad] tridagCoefs(jx, jy, kwave, a, b, c, ccoef, d, loc); } diff --git a/src/invert/laplacexy/laplacexy.cxx b/src/invert/laplacexy/laplacexy.cxx index c1bc616bb1..41b23033ec 100644 --- a/src/invert/laplacexy/laplacexy.cxx +++ b/src/invert/laplacexy/laplacexy.cxx @@ -897,13 +897,13 @@ void LaplaceXY::setMatrixElementsFiniteVolume(const Field2D& A, const Field2D& B // (1/J) d/dx ( J * g11 d/dx ) + (1/J) d/dy ( J * g22 d/dy ) auto coords = localmesh->getCoordinates(location); - const Field2D J_DC = DC(coords->J); - const Field2D g11_DC = DC(coords->g11); - const Field2D dx_DC = DC(coords->dx); - const Field2D dy_DC = DC(coords->dy); - const Field2D g_22_DC = DC(coords->g_22); - const Field2D g_23_DC = DC(coords->g_23); - const Field2D g23_DC = DC(coords->g23); + const Field2D J_DC = DC(coords->J()); + const Field2D g11_DC = DC(coords->g11()); + const Field2D dx_DC = DC(coords->dx()); + const Field2D dy_DC = DC(coords->dy()); + const Field2D g_22_DC = DC(coords->g_22()); + const Field2D g_23_DC = DC(coords->g_23()); + const Field2D g23_DC = DC(coords->g23()); for (int x = localmesh->xstart; x <= localmesh->xend; x++) { for (int y = localmesh->ystart; y <= localmesh->yend; y++) { @@ -1007,17 +1007,17 @@ void LaplaceXY::setMatrixElementsFiniteDifference(const Field2D& A, const Field2 // + B*f auto coords = localmesh->getCoordinates(location); - const Field2D G1_2D = DC(coords->G1); - const Field2D G2_2D = DC(coords->G2); - const Field2D J_2D = DC(coords->J); - const Field2D g11_2D = DC(coords->g11); - const Field2D g_22_2D = DC(coords->g_22); - const Field2D g22_2D = DC(coords->g22); - const Field2D g12_2D = DC(coords->g12); - const Field2D d1_dx_2D = DC(coords->d1_dx); - const Field2D d1_dy_2D = DC(coords->d1_dy); - const Field2D dx_2D = DC(coords->dx); - const Field2D dy_2D = DC(coords->dy); + const Field2D G1_2D = DC(coords->G1()); + const Field2D G2_2D = DC(coords->G2()); + const Field2D J_2D = DC(coords->J()); + const Field2D g11_2D = DC(coords->g11()); + const Field2D g_22_2D = DC(coords->g_22()); + const Field2D g22_2D = DC(coords->g22()); + const Field2D g12_2D = DC(coords->g12()); + const Field2D d1_dx_2D = DC(coords->d1_dx()); + const Field2D d1_dy_2D = DC(coords->d1_dy()); + const Field2D dx_2D = DC(coords->dx()); + const Field2D dy_2D = DC(coords->dy()); const Field2D coef_dfdy = G2_2D - DC(DDY(J_2D / g_22_2D) / J_2D); diff --git a/src/invert/laplacexy2/laplacexy2.cxx b/src/invert/laplacexy2/laplacexy2.cxx index 8b5e98d747..76e6437866 100644 --- a/src/invert/laplacexy2/laplacexy2.cxx +++ b/src/invert/laplacexy2/laplacexy2.cxx @@ -147,20 +147,20 @@ void LaplaceXY2::setCoefs(const Field2D& A, const Field2D& B) { // XX component // Metrics on x+1/2 boundary - BoutReal J = 0.5 * (coords->J[index] + coords->J[ind_xp]); - BoutReal g11 = 0.5 * (coords->g11[index] + coords->g11[ind_xp]); - BoutReal dx = 0.5 * (coords->dx[index] + coords->dx[ind_xp]); + BoutReal J = 0.5 * (coords->J()[index] + coords->J()[ind_xp]); + BoutReal g11 = 0.5 * (coords->g11()[index] + coords->g11()[ind_xp]); + BoutReal dx = 0.5 * (coords->dx()[index] + coords->dx()[ind_xp]); BoutReal Acoef = 0.5 * (A[index] + A[ind_xp]); - BoutReal xp = Acoef * J * g11 / (coords->J[index] * dx * coords->dx[index]); + BoutReal xp = Acoef * J * g11 / (coords->J()[index] * dx * coords->dx()[index]); // Metrics on x-1/2 boundary - J = 0.5 * (coords->J[index] + coords->J[ind_xm]); - g11 = 0.5 * (coords->g11[index] + coords->g11[ind_xm]); - dx = 0.5 * (coords->dx[index] + coords->dx[ind_xm]); + J = 0.5 * (coords->J()[index] + coords->J()[ind_xm]); + g11 = 0.5 * (coords->g11()[index] + coords->g11()[ind_xm]); + dx = 0.5 * (coords->dx()[index] + coords->dx()[ind_xm]); Acoef = 0.5 * (A[index] + A[ind_xm]); - BoutReal xm = Acoef * J * g11 / (coords->J[index] * dx * coords->dx[index]); + BoutReal xm = Acoef * J * g11 / (coords->J()[index] * dx * coords->dx()[index]); BoutReal c = B[index] - xp - xm; // Central coefficient @@ -173,28 +173,28 @@ void LaplaceXY2::setCoefs(const Field2D& A, const Field2D& B) { // YY component // Metrics at y+1/2 - J = 0.5 * (coords->J[index] + coords->J[ind_yp]); - BoutReal g_22 = 0.5 * (coords->g_22[index] + coords->g_22[ind_yp]); - BoutReal g23 = 0.5 * (coords->g23[index] + coords->g23[ind_yp]); - BoutReal g_23 = 0.5 * (coords->g_23[index] + coords->g_23[ind_yp]); - BoutReal dy = 0.5 * (coords->dy[index] + coords->dy[ind_yp]); + J = 0.5 * (coords->J()[index] + coords->J()[ind_yp]); + BoutReal g_22 = 0.5 * (coords->g_22()[index] + coords->g_22()[ind_yp]); + BoutReal g23 = 0.5 * (coords->g23()[index] + coords->g23()[ind_yp]); + BoutReal g_23 = 0.5 * (coords->g_23()[index] + coords->g_23()[ind_yp]); + BoutReal dy = 0.5 * (coords->dy()[index] + coords->dy()[ind_yp]); Acoef = 0.5 * (A[ind_yp] + A[index]); - BoutReal yp = - -Acoef * J * g23 * g_23 / (g_22 * coords->J[index] * dy * coords->dy[index]); + BoutReal yp = -Acoef * J * g23 * g_23 + / (g_22 * coords->J()[index] * dy * coords->dy()[index]); c -= yp; matrix(index, ind_yp) = yp; // Metrics at y-1/2 - J = 0.5 * (coords->J[index] + coords->J[ind_ym]); - g_22 = 0.5 * (coords->g_22[index] + coords->g_22[ind_ym]); - g23 = 0.5 * (coords->g23[index] + coords->g23[ind_ym]); - g_23 = 0.5 * (coords->g_23[index] + coords->g_23[ind_ym]); - dy = 0.5 * (coords->dy[index] + coords->dy[ind_ym]); + J = 0.5 * (coords->J()[index] + coords->J()[ind_ym]); + g_22 = 0.5 * (coords->g_22()[index] + coords->g_22()[ind_ym]); + g23 = 0.5 * (coords->g23()[index] + coords->g23()[ind_ym]); + g_23 = 0.5 * (coords->g_23()[index] + coords->g_23()[ind_ym]); + dy = 0.5 * (coords->dy()[index] + coords->dy()[ind_ym]); Acoef = 0.5 * (A[ind_ym] + A[index]); - BoutReal ym = - -Acoef * J * g23 * g_23 / (g_22 * coords->J[index] * dy * coords->dy[index]); + BoutReal ym = -Acoef * J * g23 * g_23 + / (g_22 * coords->J()[index] * dy * coords->dy()[index]); c -= ym; matrix(index, ind_ym) = ym; } diff --git a/src/invert/laplacexy2/laplacexy2_hypre.cxx b/src/invert/laplacexy2/laplacexy2_hypre.cxx index b18903be3a..f56a715ddd 100644 --- a/src/invert/laplacexy2/laplacexy2_hypre.cxx +++ b/src/invert/laplacexy2/laplacexy2_hypre.cxx @@ -106,20 +106,20 @@ void LaplaceXY2Hypre::setCoefs(const Field2D& A, const Field2D& B) { // XX component // Metrics on x+1/2 boundary - BoutReal J = 0.5 * (coords->J[index] + coords->J[ind_xp]); - BoutReal g11 = 0.5 * (coords->g11[index] + coords->g11[ind_xp]); - BoutReal dx = 0.5 * (coords->dx[index] + coords->dx[ind_xp]); + BoutReal J = 0.5 * (coords->J()[index] + coords->J()[ind_xp]); + BoutReal g11 = 0.5 * (coords->g11()[index] + coords->g11()[ind_xp]); + BoutReal dx = 0.5 * (coords->dx()[index] + coords->dx()[ind_xp]); BoutReal Acoef = 0.5 * (A[index] + A[ind_xp]); - BoutReal xp = Acoef * J * g11 / (coords->J[index] * dx * coords->dx[index]); + BoutReal xp = Acoef * J * g11 / (coords->J()[index] * dx * coords->dx()[index]); // Metrics on x-1/2 boundary - J = 0.5 * (coords->J[index] + coords->J[ind_xm]); - g11 = 0.5 * (coords->g11[index] + coords->g11[ind_xm]); - dx = 0.5 * (coords->dx[index] + coords->dx[ind_xm]); + J = 0.5 * (coords->J()[index] + coords->J()[ind_xm]); + g11 = 0.5 * (coords->g11()[index] + coords->g11()[ind_xm]); + dx = 0.5 * (coords->dx()[index] + coords->dx()[ind_xm]); Acoef = 0.5 * (A[index] + A[ind_xm]); - BoutReal xm = Acoef * J * g11 / (coords->J[index] * dx * coords->dx[index]); + BoutReal xm = Acoef * J * g11 / (coords->J()[index] * dx * coords->dx()[index]); BoutReal c = B[index] - xp - xm; // Central coefficient @@ -132,27 +132,27 @@ void LaplaceXY2Hypre::setCoefs(const Field2D& A, const Field2D& B) { // YY component // Metrics at y+1/2 - J = 0.5 * (coords->J[index] + coords->J[ind_yp]); - BoutReal g_22 = 0.5 * (coords->g_22[index] + coords->g_22[ind_yp]); - BoutReal g23 = 0.5 * (coords->g23[index] + coords->g23[ind_yp]); - BoutReal g_23 = 0.5 * (coords->g_23[index] + coords->g_23[ind_yp]); - BoutReal dy = 0.5 * (coords->dy[index] + coords->dy[ind_yp]); + J = 0.5 * (coords->J()[index] + coords->J()[ind_yp]); + BoutReal g_22 = 0.5 * (coords->g_22()[index] + coords->g_22()[ind_yp]); + BoutReal g23 = 0.5 * (coords->g23()[index] + coords->g23()[ind_yp]); + BoutReal g_23 = 0.5 * (coords->g_23()[index] + coords->g_23()[ind_yp]); + BoutReal dy = 0.5 * (coords->dy()[index] + coords->dy()[ind_yp]); Acoef = 0.5 * (A[ind_yp] + A[index]); - BoutReal yp = - -Acoef * J * g23 * g_23 / (g_22 * coords->J[index] * dy * coords->dy[index]); + BoutReal yp = -Acoef * J * g23 * g_23 + / (g_22 * coords->J()[index] * dy * coords->dy()[index]); c -= yp; // Metrics at y-1/2 - J = 0.5 * (coords->J[index] + coords->J[ind_ym]); - g_22 = 0.5 * (coords->g_22[index] + coords->g_22[ind_ym]); - g23 = 0.5 * (coords->g23[index] + coords->g23[ind_ym]); - g_23 = 0.5 * (coords->g_23[index] + coords->g_23[ind_ym]); - dy = 0.5 * (coords->dy[index] + coords->dy[ind_ym]); + J = 0.5 * (coords->J()[index] + coords->J()[ind_ym]); + g_22 = 0.5 * (coords->g_22()[index] + coords->g_22()[ind_ym]); + g23 = 0.5 * (coords->g23()[index] + coords->g23()[ind_ym]); + g_23 = 0.5 * (coords->g_23()[index] + coords->g_23()[ind_ym]); + dy = 0.5 * (coords->dy()[index] + coords->dy()[ind_ym]); Acoef = 0.5 * (A[ind_ym] + A[index]); - BoutReal ym = - -Acoef * J * g23 * g_23 / (g_22 * coords->J[index] * dy * coords->dy[index]); + BoutReal ym = -Acoef * J * g23 * g_23 + / (g_22 * coords->J()[index] * dy * coords->dy()[index]); c -= ym; M(index, ind_yp) = yp; M(index, ind_ym) = ym; diff --git a/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx b/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx index fbe22241d8..318498a161 100644 --- a/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx +++ b/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx @@ -74,7 +74,7 @@ void LaplaceXZcyclic::setCoefs(const Field2D& A2D, const Field2D& B2D) { Coordinates* coord = localmesh->getCoordinates(location); // NOTE: For now the X-Z terms are omitted, so check that they are small - ASSERT2(max(abs(coord->g13)) < 1e-5); + ASSERT2(max(abs(coord->g13())) < 1e-5); int ind = 0; const BoutReal zlength = getUniform(coord->zlength()); diff --git a/src/invert/parderiv/impls/cyclic/cyclic.cxx b/src/invert/parderiv/impls/cyclic/cyclic.cxx index 004b4f777a..7228dbe0e3 100644 --- a/src/invert/parderiv/impls/cyclic/cyclic.cxx +++ b/src/invert/parderiv/impls/cyclic/cyclic.cxx @@ -58,7 +58,7 @@ InvertParCR::InvertParCR(Options* opt, CELL_LOC location, Mesh* mesh_in) // Number of k equations to solve for each x location nsys = 1 + (localmesh->LocalNz) / 2; - sg = sqrt(localmesh->getCoordinates(location)->g_22); + sg = sqrt(localmesh->getCoordinates(location)->g_22()); sg = DDY(1. / sg) / sg; } @@ -160,7 +160,7 @@ const Field3D InvertParCR::solve(const Field3D& f) { BoutReal ecoef = E(x, y + local_ystart) + sg(x, y + local_ystart) * B(x, y + local_ystart); // ddy - if (coord->non_uniform) { + if (coord->non_uniform()) { ecoef += bcoef * coord->d1_dy(x, y + local_ystart); } diff --git a/src/invert/pardiv/impls/cyclic/pardiv_cyclic.cxx b/src/invert/pardiv/impls/cyclic/pardiv_cyclic.cxx index c17e5af64d..f1fb894ec8 100644 --- a/src/invert/pardiv/impls/cyclic/pardiv_cyclic.cxx +++ b/src/invert/pardiv/impls/cyclic/pardiv_cyclic.cxx @@ -104,9 +104,9 @@ Field3D InvertParDivCR::solve(const Field3D& f) { auto b = Matrix(nsys, size); auto c = Matrix(nsys, size); - const Field2D dy = coord->dy; - const Field2D J = coord->J; - const Field2D g_22 = coord->g_22; + const Field2D dy = coord->dy(); + const Field2D J = coord->J(); + const Field2D g_22 = coord->g_22(); const auto zlength = getUniform(coord->zlength()); // Loop over flux-surfaces diff --git a/src/mesh/boundary_standard.cxx b/src/mesh/boundary_standard.cxx index 80c2053f39..a2bcc15a36 100644 --- a/src/mesh/boundary_standard.cxx +++ b/src/mesh/boundary_standard.cxx @@ -2171,9 +2171,9 @@ void BoundaryNeumann_NonOrthogonal::apply(Field3D& f) { BoutReal delta = bndry->bx * metric->dx(bndry->x, bndry->y, zk) + bndry->by * metric->dy(bndry->x, bndry->y, zk); #else - BoutReal delta = bndry->bx * metric->dx(bndry->x, bndry->y) - + bndry->by * metric->dy(bndry->x, bndry->y); - for (int zk = 0; zk < mesh->LocalNz; zk++) { + BoutReal delta = bndry->bx * metric->dx(bndry->x, bndry->y) + + bndry->by * metric->dy(bndry->x, bndry->y); + for (int zk = 0; zk < mesh->LocalNz; zk++) { #endif if (fg) { val = fg->generate(Context(bndry, zk, loc, t, mesh)); @@ -2669,7 +2669,7 @@ void BoundaryNeumann_NonOrthogonal::apply(Field3D& f) { -1.0 * sqrt(metric->g33(x, y) / metric->g11(x, y)) * metric->dx(x, y); for (int jz = 1; jz <= ncz / 2; jz++) { BoutReal kwave = - jz * 2.0 * PI / metric->zlength()(x, y); // wavenumber in [rad^-1] + jz * 2.0 * PI / metric->zlength(x, y); // wavenumber in [rad^-1] c0[jz] *= exp(coef * kwave); // The decaying solution only } // Reverse FFT @@ -2971,13 +2971,13 @@ void BoundaryNeumann_NonOrthogonal::apply(Field3D& f) { // d/dx( Jmetric->g11 B_x ) = - d/dx( Jmetric->g12 B_y + Jmetric->g13 B_z) // - d/dy( JB^y ) - d/dz( JB^z ) - tmp = - -(metric->J(jx, jy) * metric->g12(jx, jy) * var.y(jx, jy, jz) - + metric->J(jx, jy) * metric->g13(jx, jy) * var.z(jx, jy, jz) - - metric->J(jx - 2, jy) * metric->g12(jx - 2, jy) * var.y(jx - 2, jy, jz) - + metric->J(jx - 2, jy) * metric->g13(jx - 2, jy) * var.z(jx - 2, jy, jz)) - / (metric->dx(jx - 2, jy) - + metric->dx(jx - 1, jy)); // First term (d/dx) using vals calculated above + tmp = -(metric->J(jx, jy) * metric->g12(jx, jy) * var.y(jx, jy, jz) + + metric->J(jx, jy) * metric->g13(jx, jy) * var.z(jx, jy, jz) + - metric->J(jx - 2, jy) * metric->g12(jx - 2, jy) * var.y(jx - 2, jy, jz) + + metric->J(jx - 2, jy) * metric->g13(jx - 2, jy) * var.z(jx - 2, jy, jz)) + / (metric->dx(jx - 2, jy) + + metric->dx(jx - 1, + jy)); // First term (d/dx) using vals calculated above tmp -= (metric->J(jx - 1, jy + 1) * metric->g12(jx - 1, jy + 1) * var.x(jx - 1, jy + 1, jz) - metric->J(jx - 1, jy - 1) * metric->g12(jx - 1, jy - 1) diff --git a/src/mesh/christoffel_symbols.cxx b/src/mesh/christoffel_symbols.cxx new file mode 100644 index 0000000000..a124b64c47 --- /dev/null +++ b/src/mesh/christoffel_symbols.cxx @@ -0,0 +1,91 @@ +#include "bout/christoffel_symbols.hxx" +#include "bout/coordinates.hxx" +#include "bout/derivs.hxx" +#include "bout/mesh.hxx" + +ChristoffelSymbols::ChristoffelSymbols(Coordinates& coordinates) { + // Calculate Christoffel symbol terms (18 independent values) + // Note: This calculation is completely general: metric + // tensor can be 2D or 3D. For 2D, all DDZ terms are zero + + const auto& contravariantMetricTensor = coordinates.getContravariantMetricTensor(); + const auto& covariantMetricTensor = coordinates.getCovariantMetricTensor(); + + const auto& g11 = contravariantMetricTensor.g11(); + const auto& g22 = contravariantMetricTensor.g22(); + const auto& g33 = contravariantMetricTensor.g33(); + const auto& g12 = contravariantMetricTensor.g12(); + const auto& g13 = contravariantMetricTensor.g13(); + const auto& g23 = contravariantMetricTensor.g23(); + + const auto& g_11 = covariantMetricTensor.g11(); + const auto& g_22 = covariantMetricTensor.g22(); + const auto& g_33 = covariantMetricTensor.g33(); + const auto& g_12 = covariantMetricTensor.g12(); + const auto& g_13 = covariantMetricTensor.g13(); + const auto& g_23 = covariantMetricTensor.g23(); + + G1_11_m = 0.5 * g11 * DDX(g_11) + g12 * (DDX(g_12) - 0.5 * DDY(g_11)) + + g13 * (DDX(g_13) - 0.5 * DDZ(g_11)); + G1_22_m = g11 * (DDY(g_12) - 0.5 * DDX(g_22)) + 0.5 * g12 * DDY(g_22) + + g13 * (DDY(g_23) - 0.5 * DDZ(g_22)); + G1_33_m = g11 * (DDZ(g_13) - 0.5 * DDX(g_33)) + g12 * (DDZ(g_23) - 0.5 * DDY(g_33)) + + 0.5 * g13 * DDZ(g_33); + G1_12_m = 0.5 * g11 * DDY(g_11) + 0.5 * g12 * DDX(g_22) + + 0.5 * g13 * (DDY(g_13) + DDX(g_23) - DDZ(g_12)); + G1_13_m = 0.5 * g11 * DDZ(g_11) + 0.5 * g12 * (DDZ(g_12) + DDX(g_23) - DDY(g_13)) + + 0.5 * g13 * DDX(g_33); + G1_23_m = 0.5 * g11 * (DDZ(g_12) + DDY(g_13) - DDX(g_23)) + + 0.5 * g12 * (DDZ(g_22) + DDY(g_23) - DDY(g_23)) + // + 0.5 *g13*(DDZ(g_32) + DDY(g_33) - DDZ(g_23)); + // which equals + + 0.5 * g13 * DDY(g_33); + + G2_11_m = 0.5 * g12 * DDX(g_11) + g22 * (DDX(g_12) - 0.5 * DDY(g_11)) + + g23 * (DDX(g_13) - 0.5 * DDZ(g_11)); + G2_22_m = g12 * (DDY(g_12) - 0.5 * DDX(g_22)) + 0.5 * g22 * DDY(g_22) + + g23 * (DDY(g23) - 0.5 * DDZ(g_22)); + G2_33_m = g12 * (DDZ(g_13) - 0.5 * DDX(g_33)) + g22 * (DDZ(g_23) - 0.5 * DDY(g_33)) + + 0.5 * g23 * DDZ(g_33); + G2_12_m = 0.5 * g12 * DDY(g_11) + 0.5 * g22 * DDX(g_22) + + 0.5 * g23 * (DDY(g_13) + DDX(g_23) - DDZ(g_12)); + G2_13_m = + // 0.5 *g21*(DDZ(g_11) + DDX(g13()) - DDX(g_13)) + // which equals + 0.5 * g12 * (DDZ(g_11) + DDX(g_13) - DDX(g_13)) + // + 0.5 *g22*(DDZ(g21()) + DDX(g_23) - DDY(g_13)) + // which equals + + 0.5 * g22 * (DDZ(g_12) + DDX(g_23) - DDY(g_13)) + // + 0.5 *g23*(DDZ(g31()) + DDX(g_33) - DDZ(g_13)); + // which equals + + 0.5 * g23 * DDX(g_33); + G2_23_m = 0.5 * g12 * (DDZ(g_12) + DDY(g_13) - DDX(g_23)) + 0.5 * g22 * DDZ(g_22) + + 0.5 * g23 * DDY(g_33); + + G3_11_m = 0.5 * g13 * DDX(g_11) + g23 * (DDX(g_12) - 0.5 * DDY(g_11)) + + g33 * (DDX(g_13) - 0.5 * DDZ(g_11)); + G3_22_m = g13 * (DDY(g_12) - 0.5 * DDX(g_22)) + 0.5 * g23 * DDY(g_22) + + g33 * (DDY(g_23) - 0.5 * DDZ(g_22)); + G3_33_m = g13 * (DDZ(g_13) - 0.5 * DDX(g_33)) + g23 * (DDZ(g_23) - 0.5 * DDY(g_33)) + + 0.5 * g33 * DDZ(g_33); + G3_12_m = + // 0.5 *g31*(DDY(g_11) + DDX(g12()) - DDX(g_12)) + // which equals to + 0.5 * g13 * DDY(g_11) + // + 0.5 *g32*(DDY(g21()) + DDX(g_22) - DDY(g_12)) + // which equals to + + 0.5 * g23 * DDX(g_22) + //+ 0.5 *g33*(DDY(g31()) + DDX(g32()) - DDZ(g_12)); + // which equals to + + 0.5 * g33 * (DDY(g_13)) + DDX(g_23) - DDZ(g_12); + G3_13_m = 0.5 * g13 * DDZ(g_11) + 0.5 * g23 * (DDZ(g_12) + DDX(g_23) - DDY(g_13)) + + 0.5 * g33 * DDX(g_33); + G3_23_m = 0.5 * g13 * (DDZ(g_12) + DDY(g_13)) - DDX(g_23) + 0.5 * g23 * DDZ(g_22) + + 0.5 * g33 * DDY(g_33); + + output_progress.write("\tCommunicating connection terms\n"); + + G1_11_m.getMesh()->communicate(G1_11_m, G1_22_m, G1_33_m, G1_12_m, G1_13_m, G1_23_m, + G2_11_m, G2_22_m, G2_33_m, G2_12_m, G2_13_m, G2_23_m, + G3_11_m, G3_22_m, G3_33_m, G3_12_m, G3_13_m, G3_23_m); +} diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 4e515449ca..d4df92b275 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -4,47 +4,100 @@ * given the contravariant metric tensor terms **************************************************************************/ +#include "bout/field2d.hxx" +#include "bout/g_values.hxx" #include #include #include #include -#include #include #include -#include #include #include -#include - #include "parallel/fci.hxx" #include "parallel/shiftedmetricinterp.hxx" +#include "bout/derivs.hxx" + +#include // use anonymous namespace so this utility function is not available outside this file namespace { -template + +// If the CELL_CENTRE variable was read, the staggered version is required to +// also exist for consistency +void checkStaggeredGet(Mesh* mesh, const std::string& name, const std::string& suffix) { + if (mesh->sourceHasVar(name) != mesh->sourceHasVar(name + suffix)) { + throw BoutException("Attempting to read staggered fields from grid, but " + name + + " is not present in both CELL_CENTRE and staggered versions."); + } +} + +// convenience function for repeated code +auto getAtLoc(Mesh* mesh, const std::string& name, const std::string& suffix, + CELL_LOC location, BoutReal default_value = 0.) { + + checkStaggeredGet(mesh, name, suffix); + return mesh->get(name + suffix, default_value, false, location); +} + +std::string getLocationSuffix(CELL_LOC location) { + switch (location) { + case CELL_CENTRE: { + return ""; + } + case CELL_XLOW: { + return "_xlow"; + } + case CELL_YLOW: { + return "_ylow"; + } + case CELL_ZLOW: { + // in 2D metric, same as CELL_CENTRE + return bout::build::use_metric_3d ? "_zlow" : ""; + } + default: { + throw BoutException( + "Incorrect location passed to " + "Coordinates(Mesh*,const CELL_LOC,const Coordinates*) constructor."); + } + } +} + +} // anonymous namespace + // Use sendY()/sendX() and wait() instead of Mesh::communicate() to ensure we // don't try to calculate parallel slices as Coordinates are not constructed yet -void communicate(T& t, Ts&... ts) { - FieldGroup g(t, ts...); - auto h = t.getMesh()->sendY(g); - t.getMesh()->wait(h); - h = t.getMesh()->sendX(g); - t.getMesh()->wait(h); +void Coordinates::communicate(Field2D& f) { + FieldGroup g(f); + auto* h = f.getMesh()->sendY(g); + f.getMesh()->wait(h); + h = f.getMesh()->sendX(g); + f.getMesh()->wait(h); +} +#if BOUT_USE_METRIC_3D +void Coordinates::communicate(Field3D& f) { + FieldGroup g(f); + auto* h = f.getMesh()->sendY(g); + f.getMesh()->wait(h); + h = f.getMesh()->sendX(g); + f.getMesh()->wait(h); } +#endif /// Interpolate a Field2D to a new CELL_LOC with interp_to. /// Communicates to set internal guard cells. /// Boundary guard cells are set by extrapolating from the grid, like /// 'free_o3' boundary conditions /// Corner guard cells are set to BoutNaN -Field2D interpolateAndExtrapolate(const Field2D& f, CELL_LOC location, bool extrapolate_x, - bool extrapolate_y, bool no_extra_interpolate, - ParallelTransform* UNUSED(pt) = nullptr) { +Field2D Coordinates::interpolateAndExtrapolate( + const Field2D& f, CELL_LOC location, bool extrapolate_x, bool extrapolate_y, + bool no_extra_interpolate, ParallelTransform* UNUSED(pt) = nullptr, + const std::string& region = "RGN_NOBNDRY") { Mesh* localmesh = f.getMesh(); - Field2D result = interp_to(f, location, "RGN_NOBNDRY"); + Field2D result = interp_to(f, location, region); // Ensure result's data is unique. Otherwise result might be a duplicate of // f (if no interpolation is needed, e.g. if interpolation is in the // z-direction); then f would be communicated. Since this function is used @@ -157,9 +210,10 @@ Field2D interpolateAndExtrapolate(const Field2D& f, CELL_LOC location, bool extr } #if BOUT_USE_METRIC_3D -Field3D interpolateAndExtrapolate(const Field3D& f_, CELL_LOC location, - bool extrapolate_x, bool extrapolate_y, - bool no_extra_interpolate, ParallelTransform* pt_) { +Field3D Coordinates::interpolateAndExtrapolate(const Field3D& f_, CELL_LOC location, + bool extrapolate_x, bool extrapolate_y, + bool no_extra_interpolate, + ParallelTransform* pt_) { Mesh* localmesh = f_.getMesh(); Field3D result; @@ -184,7 +238,7 @@ Field3D interpolateAndExtrapolate(const Field3D& f_, CELL_LOC location, if (location == CELL_YLOW and f.getLocation() != CELL_YLOW) { auto f_aligned = pt_f->toFieldAligned(f, "RGN_NOX"); result = interp_to(f_aligned, location, "RGN_NOBNDRY"); - ParallelTransform* pt_result; + ParallelTransform* pt_result = nullptr; if (result.getCoordinates() == nullptr) { pt_result = pt_; } else { @@ -312,99 +366,176 @@ Field3D interpolateAndExtrapolate(const Field3D& f_, CELL_LOC location, } #endif // BOUT_USE_METRIC_3D -// If the CELL_CENTRE variable was read, the staggered version is required to -// also exist for consistency -void checkStaggeredGet(Mesh* mesh, const std::string& name, const std::string& suffix) { - if (mesh->sourceHasVar(name) != mesh->sourceHasVar(name + suffix)) { - throw BoutException("Attempting to read staggered fields from grid, but " + name - + " is not present in both CELL_CENTRE and staggered versions."); - } -} +// Utility function for fixing up guard cells of zShift +void Coordinates::fixZShiftGuards(Field2D& zShift) const { + auto* localmesh = zShift.getMesh(); -// convenience function for repeated code -int getAtLoc(Mesh* mesh, Coordinates::FieldMetric& var, const std::string& name, - const std::string& suffix, CELL_LOC location, BoutReal default_value = 0.) { + // extrapolate into boundary guard cells if necessary + zShift = interpolateAndExtrapolate(zShift, zShift.getLocation(), + not localmesh->sourceHasXBoundaryGuards(), + not localmesh->sourceHasYBoundaryGuards(), false); - checkStaggeredGet(mesh, name, suffix); - int result = mesh->get(var, name + suffix, default_value, false, location); + // make sure zShift has been communicated + communicate(zShift); - return result; + // Correct guard cells for discontinuity of zShift at poloidal branch cut + for (int x = 0; x < localmesh->LocalNx; x++) { + const auto lower = localmesh->hasBranchCutLower(x); + if (lower.first) { + for (int y = 0; y < localmesh->ystart; y++) { + zShift(x, y) -= lower.second; + } + } + const auto upper = localmesh->hasBranchCutUpper(x); + if (upper.first) { + for (int y = localmesh->yend + 1; y < localmesh->LocalNy; y++) { + zShift(x, y) += upper.second; + } + } + } } -int getAtLocAndFillGuards(Mesh* mesh, Coordinates::FieldMetric& var, - const std::string& name, const std::string& suffix, - CELL_LOC location, BoutReal default_value, bool extrapolate_x, - bool extrapolate_y, bool no_extra_interpolate, - ParallelTransform* pt) { - auto ret = getAtLoc(mesh, var, name, suffix, location, default_value); - var = interpolateAndExtrapolate(var, location, extrapolate_x, extrapolate_y, - no_extra_interpolate, pt); - return ret; +Coordinates::FieldMetric Coordinates::getAtLocOrUnaligned(Mesh* mesh, + const std::string& name, + BoutReal default_value, + const std::string& suffix, + CELL_LOC cell_location) { + if (cell_location == CELL_CENTRE) { + return getUnaligned(name, default_value); + } + // grid data source has staggered fields, so read instead of interpolating + // Diagonal components of metric tensor g^{ij} (default to 1) + return getAtLoc(mesh, name, suffix, cell_location, default_value); } -std::string getLocationSuffix(CELL_LOC location) { - switch (location) { - case CELL_CENTRE: { - return ""; - } - case CELL_XLOW: { - return "_xlow"; +Coordinates::FieldMetric Coordinates::getUnaligned(const std::string& name, + BoutReal default_value) { + + auto field = localmesh->get(name, default_value, false); + if (field.getDirectionY() == YDirectionType::Aligned + and transform->canToFromFieldAligned()) { + return transform->fromFieldAligned(field); } - case CELL_YLOW: { - return "_ylow"; + field.setDirectionY(YDirectionType::Standard); + return field; +} + +Coordinates::Coordinates(Mesh* mesh, FieldMetric dx, FieldMetric dy, FieldMetric dz, + [[maybe_unused]] const FieldMetric& J, FieldMetric Bxy, + const FieldMetric& g11, const FieldMetric& g22, + const FieldMetric& g33, const FieldMetric& g12, + const FieldMetric& g13, const FieldMetric& g23, + const FieldMetric& g_11, const FieldMetric& g_22, + const FieldMetric& g_33, const FieldMetric& g_12, + const FieldMetric& g_13, const FieldMetric& g_23, + FieldMetric ShiftTorsion, FieldMetric IntShiftTorsion) + : nz(mesh->LocalNz), localmesh(mesh), location(CELL_CENTRE), dx_(std::move(dx)), + dy_(std::move(dy)), dz_(std::move(dz)), ShiftTorsion_(std::move(ShiftTorsion)), + IntShiftTorsion_(std::move(IntShiftTorsion)), + contravariantMetricTensor(g11, g22, g33, g12, g13, g23), + covariantMetricTensor(g_11, g_22, g_33, g_12, g_13, g_23), Bxy_(std::move(Bxy)) { + + // required early for differentiation. + // Identity method i.e. no transform needed + transform = bout::utils::make_unique(*localmesh); +}; + +Coordinates::Coordinates(Mesh* mesh, Options* mesh_options, const CELL_LOC loc, + const Coordinates* coords_in, bool force_interpolate_from_centre) + : localmesh(mesh), location(loc), dx_(1., mesh), dy_(1., mesh), dz_(1., mesh), + d1_dx_(mesh), d1_dy_(mesh), d1_dz_(mesh), ShiftTorsion_(mesh), + IntShiftTorsion_(mesh), contravariantMetricTensor(1., 1., 1., 0, 0, 0, mesh), + // Identity metric tensor + covariantMetricTensor(1., 1., 1., 0, 0, 0, mesh), Bxy_(1., mesh) { + + if (mesh_options == nullptr) { + mesh_options = Options::getRoot()->getSection("mesh"); } - case CELL_ZLOW: { - // in 2D metric, same as CELL_CENTRE - return bout::build::use_metric_3d ? "_zlow" : ""; + + nz = mesh->LocalNz; + + const std::string suffix = getLocationSuffix(location); + + if (coords_in == nullptr || location == CELL_CENTRE + || (!force_interpolate_from_centre && mesh->sourceHasVar("dx" + suffix))) { + + if (coords_in == nullptr) { + mesh->get(dx_, "dx", 1.0, false); + mesh->get(dy_, "dy", 1.0, false); + } + + readFromMesh(mesh_options, suffix); + + } else { + interpolateFromCoordinates(mesh_options, coords_in); } - default: { +} + +void Coordinates::interpolateFromCoordinates(Options* mesh_options, + const Coordinates* coords_in) { + + // Need to ensure parallel transform is set before differential operators are used, + // but setParallelTransform() requires that dz is already set! + if (isUniform(coords_in->dz())) { + dz_ = coords_in->dz(); + } else { throw BoutException( - "Incorrect location passed to " - "Coordinates(Mesh*,const CELL_LOC,const Coordinates*) constructor."); - } + "We are asked to transform dz to get dz before we have a transform, which might " + "require dz! \nPlease provide a dz for the staggered quantity!"); } -} -} // anonymous namespace -Coordinates::Coordinates(Mesh* mesh, FieldMetric dx, FieldMetric dy, FieldMetric dz, - FieldMetric J, FieldMetric Bxy, FieldMetric g11, FieldMetric g22, - FieldMetric g33, FieldMetric g12, FieldMetric g13, - FieldMetric g23, FieldMetric g_11, FieldMetric g_22, - FieldMetric g_33, FieldMetric g_12, FieldMetric g_13, - FieldMetric g_23, FieldMetric ShiftTorsion, - FieldMetric IntShiftTorsion) - : dx(std::move(dx)), dy(std::move(dy)), dz(dz), J(std::move(J)), Bxy(std::move(Bxy)), - g11(std::move(g11)), g22(std::move(g22)), g33(std::move(g33)), g12(std::move(g12)), - g13(std::move(g13)), g23(std::move(g23)), g_11(std::move(g_11)), - g_22(std::move(g_22)), g_33(std::move(g_33)), g_12(std::move(g_12)), - g_13(std::move(g_13)), g_23(std::move(g_23)), ShiftTorsion(std::move(ShiftTorsion)), - IntShiftTorsion(std::move(IntShiftTorsion)), nz(mesh->LocalNz), localmesh(mesh), - location(CELL_CENTRE) {} - -Coordinates::Coordinates(Mesh* mesh, Options* options) - : dx(1., mesh), dy(1., mesh), dz(1., mesh), d1_dx(mesh), d1_dy(mesh), d1_dz(mesh), - J(1., mesh), Bxy(1., mesh), - // Identity metric tensor - g11(1., mesh), g22(1., mesh), g33(1., mesh), g12(0, mesh), g13(0, mesh), - g23(0, mesh), g_11(1., mesh), g_22(1., mesh), g_33(1., mesh), g_12(0, mesh), - g_13(0, mesh), g_23(0, mesh), G1_11(mesh), G1_22(mesh), G1_33(mesh), G1_12(mesh), - G1_13(mesh), G1_23(mesh), G2_11(mesh), G2_22(mesh), G2_33(mesh), G2_12(mesh), - G2_13(mesh), G2_23(mesh), G3_11(mesh), G3_22(mesh), G3_33(mesh), G3_12(mesh), - G3_13(mesh), G3_23(mesh), G1(mesh), G2(mesh), G3(mesh), ShiftTorsion(mesh), - IntShiftTorsion(mesh), localmesh(mesh), location(CELL_CENTRE) { - - if (options == nullptr) { - options = Options::getRoot()->getSection("mesh"); + setParallelTransform(mesh_options); + + setMetricTensor(coords_in->getContravariantMetricTensor(), + coords_in->getCovariantMetricTensor()); + + std::function const + interpolateAndExtrapolate_function = [this](const FieldMetric& component) { + return interpolateAndExtrapolate(component, location, true, true, false, + transform.get()); + }; + contravariantMetricTensor.map(interpolateAndExtrapolate_function); + covariantMetricTensor.map(interpolateAndExtrapolate_function); + // Check input metrics + checkContravariant(); + checkCovariant(); + + setJ(interpolateAndExtrapolate(coords_in->J(), location, true, true, false, + transform.get())); + setBxy(interpolateAndExtrapolate(coords_in->Bxy(), location, true, true, false, + transform.get())); + + bout::checkFinite(J(), "The Jacobian", "RGN_NOCORNERS"); + bout::checkPositive(J(), "The Jacobian", "RGN_NOCORNERS"); + bout::checkFinite(Bxy(), "Bxy", "RGN_NOCORNERS"); + bout::checkPositive(Bxy(), "Bxy", "RGN_NOCORNERS"); + + ShiftTorsion_ = interpolateAndExtrapolate(coords_in->ShiftTorsion(), location, true, + true, false, transform.get()); + + if (localmesh->IncIntShear) { + IntShiftTorsion_ = interpolateAndExtrapolate(coords_in->IntShiftTorsion(), location, + true, true, false, transform.get()); } - // Note: If boundary cells were not loaded from the grid file, use - // 'interpolateAndExtrapolate' to set them. Ensures that derivatives are - // smooth at all the boundaries. + dx_ = interpolateAndExtrapolate(coords_in->dx(), location, true, true, false, + transform.get()); + dy_ = interpolateAndExtrapolate(coords_in->dy(), location, true, true, false, + transform.get()); + // not really needed - we have used dz already ... + dz_ = interpolateAndExtrapolate(coords_in->dz(), location, true, true, false, + transform.get()); +} - const bool extrapolate_x = - (*options)["extrapolate_x"].withDefault(not mesh->sourceHasXBoundaryGuards()); - const bool extrapolate_y = - (*options)["extrapolate_y"].withDefault(not mesh->sourceHasYBoundaryGuards()); +// Note: If boundary cells were not loaded from the grid file, use +// 'interpolateAndExtrapolate' to set them. Ensures that derivatives are +// smooth at all the boundaries. +void Coordinates::readFromMesh(Options* mesh_options, const std::string& suffix) { + + const bool extrapolate_x = (*mesh_options)["extrapolate_x"].withDefault( + not localmesh->sourceHasXBoundaryGuards()); + const bool extrapolate_y = (*mesh_options)["extrapolate_y"].withDefault( + not localmesh->sourceHasYBoundaryGuards()); if (extrapolate_x) { output_warn.write(_("WARNING: extrapolating input mesh quantities into x-boundary " @@ -416,977 +547,370 @@ Coordinates::Coordinates(Mesh* mesh, Options* options) "cells. Set option extrapolate_y=false to disable this.\n")); } - mesh->get(dx, "dx", 1.0, false); - mesh->get(dy, "dy", 1.0, false); - - nz = mesh->LocalNz; - - { - auto& options = Options::root(); - const bool has_zperiod = options.isSet("zperiod"); - const auto zmin = has_zperiod ? 0.0 : options["ZMIN"].withDefault(0.0); - const auto zmax = has_zperiod ? 1.0 / options["zperiod"].withDefault(1.0) - : options["ZMAX"].withDefault(1.0); - - const auto default_dz = (zmax - zmin) * TWOPI / nz; - - mesh->get(dz, "dz", default_dz, false); - } + dz_ = getDzFromOptionsFile(localmesh, suffix); // required early for differentiation. - setParallelTransform(options); + setParallelTransform(mesh_options); - dz = interpolateAndExtrapolate(dz, location, extrapolate_x, extrapolate_y, false, - transform.get()); - dx = interpolateAndExtrapolate(dx, location, extrapolate_x, extrapolate_y, false, - transform.get()); + dz_ = interpolateAndExtrapolate(dz_, location, extrapolate_x, extrapolate_y, false, + transform.get()); - if (mesh->periodicX) { - communicate(dx); - } + dx_ = getAtLocOrUnaligned(localmesh, "dx", 1.0, suffix, location); + dx_ = interpolateAndExtrapolate(dx_, location, extrapolate_x, extrapolate_y, false, + transform.get()); - dy = interpolateAndExtrapolate(dy, location, extrapolate_x, extrapolate_y, false, - transform.get()); + if (localmesh->periodicX) { + communicate(dx_); + } - auto getUnaligned = [this](auto& field, const std::string& name, - BoutReal default_value) { - localmesh->get(field, name, default_value, false); - if (field.getDirectionY() == YDirectionType::Aligned - and transform->canToFromFieldAligned()) { - return transform->fromFieldAligned(field); - } else { - return field.setDirectionY(YDirectionType::Standard); - } - }; + dy_ = getAtLocOrUnaligned(localmesh, "dy", 1.0, suffix, location); + dy_ = interpolateAndExtrapolate(dy_, location, extrapolate_x, extrapolate_y, false, + transform.get()); - auto getUnalignedAtLocation = [this, extrapolate_x, extrapolate_y, - getUnaligned](auto& field, const std::string& name, - BoutReal default_value) { - field = getUnaligned(field, name, default_value); - return interpolateAndExtrapolate(field, location, extrapolate_x, extrapolate_y, false, - transform.get()); - }; + setDx(dx_); + setDy(dy_); + setDz(dz_); + // grid data source has staggered fields, so read instead of interpolating // Diagonal components of metric tensor g^{ij} (default to 1) - g11 = getUnalignedAtLocation(g11, "g11", 1.0); - g22 = getUnalignedAtLocation(g22, "g22", 1.0); - g33 = getUnalignedAtLocation(g33, "g33", 1.0); + const auto g11 = getAtLocOrUnaligned(localmesh, "g11", 1.0, suffix, location); + const auto g22 = getAtLocOrUnaligned(localmesh, "g22", 1.0, suffix, location); + const auto g33 = getAtLocOrUnaligned(localmesh, "g33", 1.0, suffix, location); + const auto g12 = getAtLocOrUnaligned(localmesh, "g12", 0.0, suffix, location); + const auto g13 = getAtLocOrUnaligned(localmesh, "g13", 0.0, suffix, location); + const auto g23 = getAtLocOrUnaligned(localmesh, "g23", 0.0, suffix, location); + contravariantMetricTensor.setMetricTensor( + ContravariantMetricTensor(g11, g22, g33, g12, g13, g23)); - // Off-diagonal elements. Default to 0 - g12 = getUnalignedAtLocation(g12, "g12", 0.0); - g13 = getUnalignedAtLocation(g13, "g13", 0.0); - g23 = getUnalignedAtLocation(g23, "g23", 0.0); + // More robust to extrapolate derived quantities directly, rather than + // deriving from extrapolated covariant metric components + + std::function const + interpolateAndExtrapolate_function = + [this, extrapolate_y, extrapolate_x](const FieldMetric& component) { + return interpolateAndExtrapolate(component, location, extrapolate_x, + extrapolate_y, false, transform.get()); + }; + contravariantMetricTensor.map(interpolateAndExtrapolate_function); // Check input metrics checkContravariant(); /// Find covariant metric components auto covariant_component_names = {"g_11", "g_22", "g_33", "g_12", "g_13", "g_23"}; - auto source_has_component = [&mesh](const std::string& name) { - return mesh->sourceHasVar(name); + auto source_has_component = [&suffix, this](const std::string& name) { + return localmesh->sourceHasVar(name + suffix); }; - // Check if any of the components are present - if (std::any_of(begin(covariant_component_names), end(covariant_component_names), + + // Check that all components are present + if (std::all_of(begin(covariant_component_names), end(covariant_component_names), source_has_component)) { - // Check that all components are present - if (std::all_of(begin(covariant_component_names), end(covariant_component_names), - source_has_component)) { - g_11 = getUnaligned(g_11, "g_11", 1.0); - g_22 = getUnaligned(g_22, "g_22", 1.0); - g_33 = getUnaligned(g_33, "g_33", 1.0); - g_12 = getUnaligned(g_12, "g_12", 0.0); - g_13 = getUnaligned(g_13, "g_13", 0.0); - g_23 = getUnaligned(g_23, "g_23", 0.0); - - output_warn.write("\tWARNING! Covariant components of metric tensor set manually. " - "Contravariant components NOT recalculated\n"); - } else { - output_warn.write("Not all covariant components of metric tensor found. " - "Calculating all from the contravariant tensor\n"); - /// Calculate contravariant metric components if not found - if (calcCovariant("RGN_NOCORNERS")) { - throw BoutException("Error in calcCovariant call"); - } - } + const auto g_11 = getAtLocOrUnaligned(localmesh, "g_11", 1.0, suffix, location); + const auto g_22 = getAtLocOrUnaligned(localmesh, "g_22", 1.0, suffix, location); + const auto g_33 = getAtLocOrUnaligned(localmesh, "g_33", 1.0, suffix, location); + const auto g_12 = getAtLocOrUnaligned(localmesh, "g_12", 0.0, suffix, location); + const auto g_13 = getAtLocOrUnaligned(localmesh, "g_13", 0.0, suffix, location); + const auto g_23 = getAtLocOrUnaligned(localmesh, "g_23", 0.0, suffix, location); + covariantMetricTensor.setMetricTensor( + CovariantMetricTensor(g_11, g_22, g_33, g_12, g_13, g_23)); + + output_warn.write("\tWARNING! Covariant components of metric tensor set manually. " + "Contravariant components NOT recalculated\n"); } else { - /// Calculate contravariant metric components if not found - if (calcCovariant("RGN_NOCORNERS")) { - throw BoutException("Error in calcCovariant call"); - } + covariantMetricTensor.setMetricTensor(contravariantMetricTensor.inverse()); + output_warn.write("Not all covariant components of metric tensor found. " + "Calculating all from the contravariant tensor\n"); } - // More robust to extrapolate derived quantities directly, rather than - // deriving from extrapolated covariant metric components - g_11 = interpolateAndExtrapolate(g_11, location, extrapolate_x, extrapolate_y, false, - transform.get()); - g_22 = interpolateAndExtrapolate(g_22, location, extrapolate_x, extrapolate_y, false, - transform.get()); - g_33 = interpolateAndExtrapolate(g_33, location, extrapolate_x, extrapolate_y, false, - transform.get()); - g_12 = interpolateAndExtrapolate(g_12, location, extrapolate_x, extrapolate_y, false, - transform.get()); - g_13 = interpolateAndExtrapolate(g_13, location, extrapolate_x, extrapolate_y, false, - transform.get()); - g_23 = interpolateAndExtrapolate(g_23, location, extrapolate_x, extrapolate_y, false, - transform.get()); + + covariantMetricTensor.map(interpolateAndExtrapolate_function); // Check covariant metrics checkCovariant(); - /// Calculate Jacobian and Bxy - if (jacobian()) { - throw BoutException("Error in jacobian call"); - } - // Attempt to read J from the grid file - auto Jcalc = J; - if (mesh->get(J, "J", 0.0, false)) { + if (!localmesh->sourceHasVar("J" + suffix)) { + output_warn.write( - "\tWARNING: Jacobian 'J' not found. Calculating from metric tensor\n"); - J = Jcalc; - } else { - J = interpolateAndExtrapolate(J, location, extrapolate_x, extrapolate_y, false, - transform.get()); + "\tWARNING: Jacobian 'J_{:s}' not found. Calculating from metric tensor\n", + suffix); + } else { + const auto J_from_file = getAtLoc(localmesh, "J", suffix, location); // Compare calculated and loaded values - output_warn.write("\tMaximum difference in J is {:e}\n", max(abs(J - Jcalc))); - - communicate(J); + output_warn.write("\tMaximum difference in J is {:e}\n", max(abs(J() - J_from_file))); + setJ(J_from_file); - // Re-evaluate Bxy using new J - Bxy = sqrt(g_22) / J; + communicate(J()); } + // More robust to extrapolate derived quantities directly, rather than + // deriving from extrapolated covariant metric components + setJ(interpolateAndExtrapolate(J(), location, extrapolate_x, extrapolate_y, false, + transform.get())); + // Check jacobian - bout::checkFinite(J, "J", "RGN_NOCORNERS"); - bout::checkPositive(J, "J", "RGN_NOCORNERS"); - if (min(abs(J)) < 1.0e-10) { - throw BoutException("\tERROR: Jacobian becomes very small\n"); + bout::checkFinite(J(), "J" + suffix, "RGN_NOCORNERS"); + bout::checkPositive(J(), "J" + suffix, "RGN_NOCORNERS"); + if (min(abs(J())) < 1.0e-10) { + throw BoutException("\tERROR: Jacobian{:s} becomes very small\n", suffix); } // Attempt to read Bxy from the grid file - auto Bcalc = Bxy; - if (mesh->get(Bxy, "Bxy", 0.0, false)) { - output_warn.write("\tWARNING: Magnitude of B field 'Bxy' not found. Calculating from " - "metric tensor\n"); - Bxy = Bcalc; + if (!localmesh->sourceHasVar("Bxy" + suffix)) { + output_warn.write("\tWARNING: Magnitude of B field 'Bxy_{:s}' not found. " + "Calculating from metric tensor\n", + suffix); + // Re-evaluate Bxy using new J + setBxy(recalculateBxy()); } else { - - Bxy = interpolateAndExtrapolate(Bxy, location, extrapolate_x, extrapolate_y, false, - transform.get()); - output_warn.write("\tMaximum difference in Bxy is {:e}\n", max(abs(Bxy - Bcalc))); + const auto Bcalc = getAtLoc(localmesh, "Bxy", suffix, location); + setBxy(Bcalc); + output_warn.write("\tMaximum difference in Bxy is {:e}\n", max(abs(Bxy() - Bcalc))); } + setBxy(interpolateAndExtrapolate(Bxy(), location, extrapolate_x, extrapolate_y, false, + transform.get())); + // Check Bxy - bout::checkFinite(Bxy, "Bxy", "RGN_NOCORNERS"); - bout::checkPositive(Bxy, "Bxy", "RGN_NOCORNERS"); + bout::checkFinite(Bxy(), "Bxy" + suffix, "RGN_NOCORNERS"); + bout::checkPositive(Bxy(), "Bxy" + suffix, "RGN_NOCORNERS"); - if (mesh->get(ShiftTorsion, "ShiftTorsion", 0.0, false)) { - output_warn.write( - "\tWARNING: No Torsion specified for zShift. Derivatives may not be correct\n"); - ShiftTorsion = 0.0; + if (!localmesh->sourceHasVar("ShiftTorsion" + suffix)) { + output_warn.write("\tWARNING: No Torsion specified for zShift. " + "Derivatives may not be correct\n"); + ShiftTorsion_ = (0.0); + } else { + const auto shift_torsion = getAtLoc(localmesh, "ShiftTorsion", suffix, location, 0.0); } - ShiftTorsion = interpolateAndExtrapolate(ShiftTorsion, location, extrapolate_x, - extrapolate_y, false, transform.get()); - - ////////////////////////////////////////////////////// + ShiftTorsion_ = (interpolateAndExtrapolate(ShiftTorsion(), location, extrapolate_x, + extrapolate_y, false, transform.get())); - if (mesh->IncIntShear) { - if (mesh->get(IntShiftTorsion, "IntShiftTorsion", 0.0, false)) { - output_warn.write("\tWARNING: No Integrated torsion specified\n"); - } - IntShiftTorsion = interpolateAndExtrapolate(IntShiftTorsion, location, extrapolate_x, - extrapolate_y, false, transform.get()); + if (!localmesh->IncIntShear) { + return; + } + if (!localmesh->sourceHasVar("IntShiftTorsion" + suffix)) { + output_warn.write("\tWARNING: No Integrated torsion specified\n"); + IntShiftTorsion_ = 0.0; } else { - // IntShiftTorsion will not be used, but set to zero to avoid uninitialized field - IntShiftTorsion = 0.; + const auto shift_torsion = + getAtLoc(localmesh, "IntShiftTorsion", suffix, location, 0.0); } + setIntShiftTorsion(interpolateAndExtrapolate(IntShiftTorsion(), location, extrapolate_x, + extrapolate_y, false, transform.get())); } -Coordinates::Coordinates(Mesh* mesh, Options* options, const CELL_LOC loc, - const Coordinates* coords_in, bool force_interpolate_from_centre) - : dx(1., mesh), dy(1., mesh), dz(1., mesh), d1_dx(mesh), d1_dy(mesh), d1_dz(mesh), - J(1., mesh), Bxy(1., mesh), - // Identity metric tensor - g11(1., mesh), g22(1., mesh), g33(1., mesh), g12(0, mesh), g13(0, mesh), - g23(0, mesh), g_11(1., mesh), g_22(1., mesh), g_33(1., mesh), g_12(0, mesh), - g_13(0, mesh), g_23(0, mesh), G1_11(mesh), G1_22(mesh), G1_33(mesh), G1_12(mesh), - G1_13(mesh), G1_23(mesh), G2_11(mesh), G2_22(mesh), G2_33(mesh), G2_12(mesh), - G2_13(mesh), G2_23(mesh), G3_11(mesh), G3_22(mesh), G3_33(mesh), G3_12(mesh), - G3_13(mesh), G3_23(mesh), G1(mesh), G2(mesh), G3(mesh), ShiftTorsion(mesh), - IntShiftTorsion(mesh), localmesh(mesh), location(loc) { - - std::string suffix = getLocationSuffix(location); - - nz = mesh->LocalNz; - - // Default to true in case staggered quantities are not read from file - bool extrapolate_x = true; - bool extrapolate_y = true; - - if (!force_interpolate_from_centre && mesh->sourceHasVar("dx" + suffix)) { - - extrapolate_x = not mesh->sourceHasXBoundaryGuards(); - extrapolate_y = not mesh->sourceHasYBoundaryGuards(); - - if (extrapolate_x) { - output_warn.write(_("WARNING: extrapolating input mesh quantities into x-boundary " - "cells\n")); - } - - if (extrapolate_y) { - output_warn.write(_("WARNING: extrapolating input mesh quantities into y-boundary " - "cells\n")); - } - - { - auto& options = Options::root(); - const bool has_zperiod = options.isSet("zperiod"); - const auto zmin = has_zperiod ? 0.0 : options["ZMIN"].withDefault(0.0); - const auto zmax = has_zperiod ? 1.0 / options["zperiod"].withDefault(1.0) - : options["ZMAX"].withDefault(1.0); - - const auto default_dz = (zmax - zmin) * TWOPI / nz; - getAtLoc(mesh, dz, "dz", suffix, location, default_dz); - } - setParallelTransform(options); - - dz = interpolateAndExtrapolate(dz, location, extrapolate_x, extrapolate_y, false, - transform.get()); - - getAtLocAndFillGuards(mesh, dx, "dx", suffix, location, 1.0, extrapolate_x, - extrapolate_y, false, transform.get()); - - if (mesh->periodicX) { - communicate(dx); - } - - getAtLocAndFillGuards(mesh, dy, "dy", suffix, location, 1.0, extrapolate_x, - extrapolate_y, false, transform.get()); - - // grid data source has staggered fields, so read instead of interpolating - // Diagonal components of metric tensor g^{ij} (default to 1) - getAtLocAndFillGuards(mesh, g11, "g11", suffix, location, 1.0, extrapolate_x, - extrapolate_y, false, transform.get()); - getAtLocAndFillGuards(mesh, g22, "g22", suffix, location, 1.0, extrapolate_x, - extrapolate_y, false, transform.get()); - getAtLocAndFillGuards(mesh, g33, "g33", suffix, location, 1.0, extrapolate_x, - extrapolate_y, false, transform.get()); - getAtLocAndFillGuards(mesh, g12, "g12", suffix, location, 0.0, extrapolate_x, - extrapolate_y, false, transform.get()); - getAtLocAndFillGuards(mesh, g13, "g13", suffix, location, 0.0, extrapolate_x, - extrapolate_y, false, transform.get()); - getAtLocAndFillGuards(mesh, g23, "g23", suffix, location, 0.0, extrapolate_x, - extrapolate_y, false, transform.get()); - - // Check input metrics - checkContravariant(); - - /// Find covariant metric components - auto covariant_component_names = {"g_11", "g_22", "g_33", "g_12", "g_13", "g_23"}; - auto source_has_component = [&suffix, &mesh](const std::string& name) { - return mesh->sourceHasVar(name + suffix); - }; - // Check if any of the components are present - if (std::any_of(begin(covariant_component_names), end(covariant_component_names), - source_has_component)) { - // Check that all components are present - if (std::all_of(begin(covariant_component_names), end(covariant_component_names), - source_has_component)) { - - getAtLoc(mesh, g_11, "g_11", suffix, location); - getAtLoc(mesh, g_22, "g_22", suffix, location); - getAtLoc(mesh, g_33, "g_33", suffix, location); - getAtLoc(mesh, g_12, "g_12", suffix, location); - getAtLoc(mesh, g_13, "g_13", suffix, location); - getAtLoc(mesh, g_23, "g_23", suffix, location); - - output_warn.write( - "\tWARNING! Staggered covariant components of metric tensor set manually. " - "Contravariant components NOT recalculated\n"); - - } else { - output_warn.write( - "Not all staggered covariant components of metric tensor found. " - "Calculating all from the contravariant tensor\n"); - /// Calculate contravariant metric components if not found - if (calcCovariant("RGN_NOCORNERS")) { - throw BoutException("Error in staggered calcCovariant call"); - } - } - } else { - /// Calculate contravariant metric components if not found - if (calcCovariant("RGN_NOCORNERS")) { - throw BoutException("Error in staggered calcCovariant call"); - } - } - // More robust to extrapolate derived quantities directly, rather than - // deriving from extrapolated covariant metric components - g_11 = interpolateAndExtrapolate(g_11, location, extrapolate_x, extrapolate_y, false, - transform.get()); - g_22 = interpolateAndExtrapolate(g_22, location, extrapolate_x, extrapolate_y, false, - transform.get()); - g_33 = interpolateAndExtrapolate(g_33, location, extrapolate_x, extrapolate_y, false, - transform.get()); - g_12 = interpolateAndExtrapolate(g_12, location, extrapolate_x, extrapolate_y, false, - transform.get()); - g_13 = interpolateAndExtrapolate(g_13, location, extrapolate_x, extrapolate_y, false, - transform.get()); - g_23 = interpolateAndExtrapolate(g_23, location, extrapolate_x, extrapolate_y, false, - transform.get()); - - // Check covariant metrics - checkCovariant(); - - /// Calculate Jacobian and Bxy - if (jacobian()) { - throw BoutException("Error in jacobian call while constructing staggered " - "Coordinates"); - } - - // Attempt to read J from the grid file - auto Jcalc = J; - if (getAtLoc(mesh, J, "J", suffix, location)) { - output_warn.write( - "\tWARNING: Jacobian 'J_{:s}' not found. Calculating from metric tensor\n", - suffix); - J = Jcalc; - } else { - J = interpolateAndExtrapolate(J, location, extrapolate_x, extrapolate_y, false, - transform.get()); - - // Compare calculated and loaded values - output_warn.write("\tMaximum difference in J is %e\n", max(abs(J - Jcalc))); - - // Re-evaluate Bxy using new J - Bxy = sqrt(g_22) / J; - } - - // Check jacobian - bout::checkFinite(J, "J" + suffix, "RGN_NOCORNERS"); - bout::checkPositive(J, "J" + suffix, "RGN_NOCORNERS"); - if (min(abs(J)) < 1.0e-10) { - throw BoutException("\tERROR: Jacobian{:s} becomes very small\n", suffix); - } - - // Attempt to read Bxy from the grid file - auto Bcalc = Bxy; - if (getAtLoc(mesh, Bxy, "Bxy", suffix, location)) { - output_warn.write( - "\tWARNING: Magnitude of B field 'Bxy_{:s}' not found. Calculating " - " from metric tensor\n", - suffix); - Bxy = Bcalc; - } else { - Bxy = interpolateAndExtrapolate(Bxy, location, extrapolate_x, extrapolate_y, false, - transform.get()); - - output_warn.write("\tMaximum difference in Bxy is %e\n", max(abs(Bxy - Bcalc))); - } - - // Check Bxy - bout::checkFinite(Bxy, "Bxy" + suffix, "RGN_NOCORNERS"); - bout::checkPositive(Bxy, "Bxy" + suffix, "RGN_NOCORNERS"); - - checkStaggeredGet(mesh, "ShiftTorsion", suffix); - if (mesh->get(ShiftTorsion, "ShiftTorsion" + suffix, 0.0, false)) { - output_warn.write( - "\tWARNING: No Torsion specified for zShift. Derivatives may not be correct\n"); - ShiftTorsion = 0.0; - } - ShiftTorsion.setLocation(location); - ShiftTorsion = interpolateAndExtrapolate(ShiftTorsion, location, extrapolate_x, - extrapolate_y, false, transform.get()); - - ////////////////////////////////////////////////////// - - if (mesh->IncIntShear) { - checkStaggeredGet(mesh, "IntShiftTorsion", suffix); - if (mesh->get(IntShiftTorsion, "IntShiftTorsion" + suffix, 0.0, false)) { - output_warn.write("\tWARNING: No Integrated torsion specified\n"); - IntShiftTorsion = 0.0; - } - IntShiftTorsion.setLocation(location); - IntShiftTorsion = - interpolateAndExtrapolate(IntShiftTorsion, location, extrapolate_x, - extrapolate_y, false, transform.get()); - } else { - // IntShiftTorsion will not be used, but set to zero to avoid uninitialized field - IntShiftTorsion = 0.; - } - } else { - // Interpolate fields from coords_in - - if (isUniform(coords_in->dz)) { - dz = coords_in->dz; - dz.setLocation(location); - } else { - throw BoutException( - "We are asked to transform dz to get dz before we have a transform, which " - "might require dz!\nPlease provide a dz for the staggered quantity!"); - } - setParallelTransform(options); - dx = interpolateAndExtrapolate(coords_in->dx, location, true, true, false, - transform.get()); - dy = interpolateAndExtrapolate(coords_in->dy, location, true, true, false, - transform.get()); - // not really needed - we have used dz already ... - dz = interpolateAndExtrapolate(coords_in->dz, location, true, true, false, - transform.get()); - - // Diagonal components of metric tensor g^{ij} - g11 = interpolateAndExtrapolate(coords_in->g11, location, true, true, false, - transform.get()); - g22 = interpolateAndExtrapolate(coords_in->g22, location, true, true, false, - transform.get()); - g33 = interpolateAndExtrapolate(coords_in->g33, location, true, true, false, - transform.get()); - - // Off-diagonal elements. - g12 = interpolateAndExtrapolate(coords_in->g12, location, true, true, false, - transform.get()); - g13 = interpolateAndExtrapolate(coords_in->g13, location, true, true, false, - transform.get()); - g23 = interpolateAndExtrapolate(coords_in->g23, location, true, true, false, - transform.get()); - - // 3x3 matrix inversion can exaggerate small interpolation errors, so it is - // more robust to interpolate and extrapolate derived quantities directly, - // rather than deriving from interpolated/extrapolated covariant metric - // components - g_11 = interpolateAndExtrapolate(coords_in->g_11, location, true, true, false, - transform.get()); - g_22 = interpolateAndExtrapolate(coords_in->g_22, location, true, true, false, - transform.get()); - g_33 = interpolateAndExtrapolate(coords_in->g_33, location, true, true, false, - transform.get()); - g_12 = interpolateAndExtrapolate(coords_in->g_12, location, true, true, false, - transform.get()); - g_13 = interpolateAndExtrapolate(coords_in->g_13, location, true, true, false, - transform.get()); - g_23 = interpolateAndExtrapolate(coords_in->g_23, location, true, true, false, - transform.get()); - - // Check input metrics - checkContravariant(); - checkCovariant(); - - J = interpolateAndExtrapolate(coords_in->J, location, true, true, false, - transform.get()); - Bxy = interpolateAndExtrapolate(coords_in->Bxy, location, true, true, false, - transform.get()); +FieldMetric Coordinates::getDzFromOptionsFile(Mesh* mesh, + const std::string& suffix) const { - bout::checkFinite(J, "The Jacobian", "RGN_NOCORNERS"); - bout::checkPositive(J, "The Jacobian", "RGN_NOCORNERS"); - bout::checkFinite(Bxy, "Bxy", "RGN_NOCORNERS"); - bout::checkPositive(Bxy, "Bxy", "RGN_NOCORNERS"); + auto& options_root = Options::root(); + const bool has_zperiod = options_root.isSet("zperiod"); + const auto zmin = has_zperiod ? 0.0 : options_root["ZMIN"].withDefault(0.0); + const auto zmax = has_zperiod ? 1.0 / options_root["zperiod"].withDefault(1.0) + : options_root["ZMAX"].withDefault(1.0); - ShiftTorsion = interpolateAndExtrapolate(coords_in->ShiftTorsion, location, true, - true, false, transform.get()); - - if (mesh->IncIntShear) { - IntShiftTorsion = interpolateAndExtrapolate(coords_in->IntShiftTorsion, location, - true, true, false, transform.get()); - } - } + const auto default_dz = (zmax - zmin) * TWOPI / nz; + FieldMetric dz = getAtLoc(mesh, "dz", suffix, location, default_dz); + return dz; } void Coordinates::outputVars(Options& output_options) { - Timer time("io"); + Timer const time("io"); const std::string loc_string = (location == CELL_CENTRE) ? "" : "_" + toString(location); - output_options["dx" + loc_string].force(dx, "Coordinates"); - output_options["dy" + loc_string].force(dy, "Coordinates"); - output_options["dz" + loc_string].force(dz, "Coordinates"); + output_options["dx" + loc_string].force(dx(), "Coordinates"); + output_options["dy" + loc_string].force(dy(), "Coordinates"); + output_options["dz" + loc_string].force(dz(), "Coordinates"); - output_options["g11" + loc_string].force(g11, "Coordinates"); - output_options["g22" + loc_string].force(g22, "Coordinates"); - output_options["g33" + loc_string].force(g33, "Coordinates"); - output_options["g12" + loc_string].force(g12, "Coordinates"); - output_options["g13" + loc_string].force(g13, "Coordinates"); - output_options["g23" + loc_string].force(g23, "Coordinates"); + output_options["g11" + loc_string].force(g11(), "Coordinates"); + output_options["g22" + loc_string].force(g22(), "Coordinates"); + output_options["g33" + loc_string].force(g33(), "Coordinates"); + output_options["g12" + loc_string].force(g12(), "Coordinates"); + output_options["g13" + loc_string].force(g13(), "Coordinates"); + output_options["g23" + loc_string].force(g23(), "Coordinates"); - output_options["g_11" + loc_string].force(g_11, "Coordinates"); - output_options["g_22" + loc_string].force(g_22, "Coordinates"); - output_options["g_33" + loc_string].force(g_33, "Coordinates"); - output_options["g_12" + loc_string].force(g_12, "Coordinates"); - output_options["g_13" + loc_string].force(g_13, "Coordinates"); - output_options["g_23" + loc_string].force(g_23, "Coordinates"); + output_options["g_11" + loc_string].force(g_11(), "Coordinates"); + output_options["g_22" + loc_string].force(g_22(), "Coordinates"); + output_options["g_33" + loc_string].force(g_33(), "Coordinates"); + output_options["g_12" + loc_string].force(g_12(), "Coordinates"); + output_options["g_13" + loc_string].force(g_13(), "Coordinates"); + output_options["g_23" + loc_string].force(g_23(), "Coordinates"); - output_options["J" + loc_string].force(J, "Coordinates"); - output_options["Bxy" + loc_string].force(Bxy, "Coordinates"); + output_options["J" + loc_string].force(J(), "Coordinates"); + output_options["Bxy" + loc_string].force(Bxy(), "Coordinates"); - output_options["G1" + loc_string].force(G1, "Coordinates"); - output_options["G2" + loc_string].force(G2, "Coordinates"); - output_options["G3" + loc_string].force(G3, "Coordinates"); + output_options["G1" + loc_string].force(G1(), "Coordinates"); + output_options["G2" + loc_string].force(G2(), "Coordinates"); + output_options["G3" + loc_string].force(G3(), "Coordinates"); getParallelTransform().outputVars(output_options); } const Field2D& Coordinates::zlength() const { - BOUT_OMP_SAFE(critical) + BOUT_OMP(critical) if (not zlength_cache) { zlength_cache = std::make_unique(0., localmesh); #if BOUT_USE_METRIC_3D - BOUT_FOR_SERIAL(i, dz.getRegion("RGN_ALL")) { (*zlength_cache)[i] += dz[i]; } + BOUT_FOR_SERIAL(i, dz().getRegion("RGN_ALL")) { (*zlength_cache)[i] += dz()[i]; } #else - (*zlength_cache) = dz * nz; + (*zlength_cache) = dz_ * nz; #endif } return *zlength_cache; } -int Coordinates::geometry(bool recalculate_staggered, - bool force_interpolate_from_centre) { - TRACE("Coordinates::geometry"); - communicate(dx, dy, dz, g11, g22, g33, g12, g13, g23, g_11, g_22, g_33, g_12, g_13, - g_23, J, Bxy); - - output_progress.write("Calculating differential geometry terms\n"); - +void Coordinates::setDx(FieldMetric dx) { if (min(abs(dx)) < 1e-8) { throw BoutException("dx magnitude less than 1e-8"); } + dx_ = std::move(dx); + localmesh->communicate(dx_); +} + +void Coordinates::setDy(FieldMetric dy) { if (min(abs(dy)) < 1e-8) { throw BoutException("dy magnitude less than 1e-8"); } + dy_ = std::move(dy); + localmesh->communicate(dy_); +} + +void Coordinates::setDz(FieldMetric dz) { if (min(abs(dz)) < 1e-8) { throw BoutException("dz magnitude less than 1e-8"); } + dz_ = std::move(dz); + localmesh->communicate(dz_); +} + +void Coordinates::recalculateAndReset(bool recalculate_staggered, + bool force_interpolate_from_centre) { + // Check input metrics checkContravariant(); checkCovariant(); - // Calculate Christoffel symbol terms (18 independent values) - // Note: This calculation is completely general: metric - // tensor can be 2D or 3D. For 2D, all DDZ terms are zero - - G1_11 = 0.5 * g11 * DDX(g_11) + g12 * (DDX(g_12) - 0.5 * DDY(g_11)) - + g13 * (DDX(g_13) - 0.5 * DDZ(g_11)); - G1_22 = g11 * (DDY(g_12) - 0.5 * DDX(g_22)) + 0.5 * g12 * DDY(g_22) - + g13 * (DDY(g_23) - 0.5 * DDZ(g_22)); - G1_33 = g11 * (DDZ(g_13) - 0.5 * DDX(g_33)) + g12 * (DDZ(g_23) - 0.5 * DDY(g_33)) - + 0.5 * g13 * DDZ(g_33); - G1_12 = 0.5 * g11 * DDY(g_11) + 0.5 * g12 * DDX(g_22) - + 0.5 * g13 * (DDY(g_13) + DDX(g_23) - DDZ(g_12)); - G1_13 = 0.5 * g11 * DDZ(g_11) + 0.5 * g12 * (DDZ(g_12) + DDX(g_23) - DDY(g_13)) - + 0.5 * g13 * DDX(g_33); - G1_23 = 0.5 * g11 * (DDZ(g_12) + DDY(g_13) - DDX(g_23)) - + 0.5 * g12 * (DDZ(g_22) + DDY(g_23) - DDY(g_23)) - // + 0.5 *g13*(DDZ(g_32) + DDY(g_33) - DDZ(g_23)); - // which equals - + 0.5 * g13 * DDY(g_33); - - G2_11 = 0.5 * g12 * DDX(g_11) + g22 * (DDX(g_12) - 0.5 * DDY(g_11)) - + g23 * (DDX(g_13) - 0.5 * DDZ(g_11)); - G2_22 = g12 * (DDY(g_12) - 0.5 * DDX(g_22)) + 0.5 * g22 * DDY(g_22) - + g23 * (DDY(g23) - 0.5 * DDZ(g_22)); - G2_33 = g12 * (DDZ(g_13) - 0.5 * DDX(g_33)) + g22 * (DDZ(g_23) - 0.5 * DDY(g_33)) - + 0.5 * g23 * DDZ(g_33); - G2_12 = 0.5 * g12 * DDY(g_11) + 0.5 * g22 * DDX(g_22) - + 0.5 * g23 * (DDY(g_13) + DDX(g_23) - DDZ(g_12)); - G2_13 = - // 0.5 *g21*(DDZ(g_11) + DDX(g_13) - DDX(g_13)) - // which equals - 0.5 * g12 * (DDZ(g_11) + DDX(g_13) - DDX(g_13)) - // + 0.5 *g22*(DDZ(g_21) + DDX(g_23) - DDY(g_13)) - // which equals - + 0.5 * g22 * (DDZ(g_12) + DDX(g_23) - DDY(g_13)) - // + 0.5 *g23*(DDZ(g_31) + DDX(g_33) - DDZ(g_13)); - // which equals - + 0.5 * g23 * DDX(g_33); - G2_23 = 0.5 * g12 * (DDZ(g_12) + DDY(g_13) - DDX(g_23)) + 0.5 * g22 * DDZ(g_22) - + 0.5 * g23 * DDY(g_33); - - G3_11 = 0.5 * g13 * DDX(g_11) + g23 * (DDX(g_12) - 0.5 * DDY(g_11)) - + g33 * (DDX(g_13) - 0.5 * DDZ(g_11)); - G3_22 = g13 * (DDY(g_12) - 0.5 * DDX(g_22)) + 0.5 * g23 * DDY(g_22) - + g33 * (DDY(g_23) - 0.5 * DDZ(g_22)); - G3_33 = g13 * (DDZ(g_13) - 0.5 * DDX(g_33)) + g23 * (DDZ(g_23) - 0.5 * DDY(g_33)) - + 0.5 * g33 * DDZ(g_33); - G3_12 = - // 0.5 *g31*(DDY(g_11) + DDX(g_12) - DDX(g_12)) - // which equals to - 0.5 * g13 * DDY(g_11) - // + 0.5 *g32*(DDY(g_21) + DDX(g_22) - DDY(g_12)) - // which equals to - + 0.5 * g23 * DDX(g_22) - //+ 0.5 *g33*(DDY(g_31) + DDX(g_32) - DDZ(g_12)); - // which equals to - + 0.5 * g33 * (DDY(g_13) + DDX(g_23) - DDZ(g_12)); - G3_13 = 0.5 * g13 * DDZ(g_11) + 0.5 * g23 * (DDZ(g_12) + DDX(g_23) - DDY(g_13)) - + 0.5 * g33 * DDX(g_33); - G3_23 = 0.5 * g13 * (DDZ(g_12) + DDY(g_13) - DDX(g_23)) + 0.5 * g23 * DDZ(g_22) - + 0.5 * g33 * DDY(g_33); - - auto tmp = J * g12; - communicate(tmp); - G1 = (DDX(J * g11) + DDY(tmp) + DDZ(J * g13)) / J; - tmp = J * g22; - communicate(tmp); - G2 = (DDX(J * g12) + DDY(tmp) + DDZ(J * g23)) / J; - tmp = J * g23; - communicate(tmp); - G3 = (DDX(J * g13) + DDY(tmp) + DDZ(J * g33)) / J; - - // Communicate christoffel symbol terms - output_progress.write("\tCommunicating connection terms\n"); - - communicate(G1_11, G1_22, G1_33, G1_12, G1_13, G1_23, G2_11, G2_22, G2_33, G2_12, G2_13, - G2_23, G3_11, G3_22, G3_33, G3_12, G3_13, G3_23, G1, G2, G3); - - // Set boundary guard cells of Christoffel symbol terms - // Ideally, when location is staggered, we would set the upper/outer boundary point - // correctly rather than by extrapolating here: e.g. if location==CELL_YLOW and we are - // at the upper y-boundary the x- and z-derivatives at yend+1 at the boundary can be - // calculated because the guard cells are available, while the y-derivative could be - // calculated from the CELL_CENTRE metric components (which have guard cells available - // past the boundary location). This would avoid the problem that the y-boundary on the - // CELL_YLOW grid is at a 'guard cell' location (yend+1). - // However, the above would require lots of special handling, so just extrapolate for - // now. - G1_11 = interpolateAndExtrapolate(G1_11, location, true, true, true, transform.get()); - G1_22 = interpolateAndExtrapolate(G1_22, location, true, true, true, transform.get()); - G1_33 = interpolateAndExtrapolate(G1_33, location, true, true, true, transform.get()); - G1_12 = interpolateAndExtrapolate(G1_12, location, true, true, true, transform.get()); - G1_13 = interpolateAndExtrapolate(G1_13, location, true, true, true, transform.get()); - G1_23 = interpolateAndExtrapolate(G1_23, location, true, true, true, transform.get()); - - G2_11 = interpolateAndExtrapolate(G2_11, location, true, true, true, transform.get()); - G2_22 = interpolateAndExtrapolate(G2_22, location, true, true, true, transform.get()); - G2_33 = interpolateAndExtrapolate(G2_33, location, true, true, true, transform.get()); - G2_12 = interpolateAndExtrapolate(G2_12, location, true, true, true, transform.get()); - G2_13 = interpolateAndExtrapolate(G2_13, location, true, true, true, transform.get()); - G2_23 = interpolateAndExtrapolate(G2_23, location, true, true, true, transform.get()); - - G3_11 = interpolateAndExtrapolate(G3_11, location, true, true, true, transform.get()); - G3_22 = interpolateAndExtrapolate(G3_22, location, true, true, true, transform.get()); - G3_33 = interpolateAndExtrapolate(G3_33, location, true, true, true, transform.get()); - G3_12 = interpolateAndExtrapolate(G3_12, location, true, true, true, transform.get()); - G3_13 = interpolateAndExtrapolate(G3_13, location, true, true, true, transform.get()); - G3_23 = interpolateAndExtrapolate(G3_23, location, true, true, true, transform.get()); - - G1 = interpolateAndExtrapolate(G1, location, true, true, true, transform.get()); - G2 = interpolateAndExtrapolate(G2, location, true, true, true, transform.get()); - G3 = interpolateAndExtrapolate(G3, location, true, true, true, transform.get()); - - ////////////////////////////////////////////////////// - /// Non-uniform meshes. Need to use DDX, DDY - - OPTION(Options::getRoot(), non_uniform, true); - - Coordinates::FieldMetric d2x(localmesh), d2y(localmesh), - d2z(localmesh); // d^2 x / d i^2 + christoffel_symbols_cache.reset(); + g_values_cache.reset(); - // Read correction for non-uniform meshes - std::string suffix = getLocationSuffix(location); - if (location == CELL_CENTRE - or (!force_interpolate_from_centre and localmesh->sourceHasVar("dx" + suffix))) { - bool extrapolate_x = not localmesh->sourceHasXBoundaryGuards(); - bool extrapolate_y = not localmesh->sourceHasYBoundaryGuards(); - - if (localmesh->get(d2x, "d2x" + suffix, 0.0, false, location)) { - output_warn.write( - "\tWARNING: differencing quantity 'd2x' not found. Calculating from dx\n"); - d1_dx = bout::derivatives::index::DDX(1. / dx); // d/di(1/dx) - - communicate(d1_dx); - d1_dx = - interpolateAndExtrapolate(d1_dx, location, true, true, true, transform.get()); - } else { - d2x.setLocation(location); - // set boundary cells if necessary - d2x = interpolateAndExtrapolate(d2x, location, extrapolate_x, extrapolate_y, false, - transform.get()); - - d1_dx = -d2x / (dx * dx); - } - - if (localmesh->get(d2y, "d2y" + suffix, 0.0, false, location)) { - output_warn.write( - "\tWARNING: differencing quantity 'd2y' not found. Calculating from dy\n"); - d1_dy = DDY(1. / dy); // d/di(1/dy) - - communicate(d1_dy); - d1_dy = - interpolateAndExtrapolate(d1_dy, location, true, true, true, transform.get()); - } else { - d2y.setLocation(location); - // set boundary cells if necessary - d2y = interpolateAndExtrapolate(d2y, location, extrapolate_x, extrapolate_y, false, - transform.get()); - - d1_dy = -d2y / (dy * dy); - } - -#if BOUT_USE_METRIC_3D - if (localmesh->get(d2z, "d2z" + suffix, 0.0, false)) { - output_warn.write( - "\tWARNING: differencing quantity 'd2z' not found. Calculating from dz\n"); - d1_dz = bout::derivatives::index::DDZ(1. / dz); - communicate(d1_dz); - d1_dz = - interpolateAndExtrapolate(d1_dz, location, true, true, true, transform.get()); - } else { - d2z.setLocation(location); - // set boundary cells if necessary - d2z = interpolateAndExtrapolate(d2z, location, extrapolate_x, extrapolate_y, false, - transform.get()); - - d1_dz = -d2z / (dz * dz); - } -#else - d1_dz = 0; -#endif - } else { - if (localmesh->get(d2x, "d2x", 0.0, false)) { - output_warn.write( - "\tWARNING: differencing quantity 'd2x' not found. Calculating from dx\n"); - d1_dx = bout::derivatives::index::DDX(1. / dx); // d/di(1/dx) - - communicate(d1_dx); - d1_dx = - interpolateAndExtrapolate(d1_dx, location, true, true, true, transform.get()); - } else { - // Shift d2x to our location - d2x = interpolateAndExtrapolate(d2x, location, true, true, false, transform.get()); - - d1_dx = -d2x / (dx * dx); - } - - if (localmesh->get(d2y, "d2y", 0.0, false)) { - output_warn.write( - "\tWARNING: differencing quantity 'd2y' not found. Calculating from dy\n"); - d1_dy = DDY(1. / dy); // d/di(1/dy) - - communicate(d1_dy); - d1_dy = - interpolateAndExtrapolate(d1_dy, location, true, true, true, transform.get()); - } else { - // Shift d2y to our location - d2y = interpolateAndExtrapolate(d2y, location, true, true, false, transform.get()); - - d1_dy = -d2y / (dy * dy); - } - -#if BOUT_USE_METRIC_3D - if (localmesh->get(d2z, "d2z", 0.0, false)) { - output_warn.write( - "\tWARNING: differencing quantity 'd2z' not found. Calculating from dz\n"); - d1_dz = bout::derivatives::index::DDZ(1. / dz); - - communicate(d1_dz); - d1_dz = - interpolateAndExtrapolate(d1_dz, location, true, true, true, transform.get()); - } else { - // Shift d2z to our location - d2z = interpolateAndExtrapolate(d2z, location, true, true, false, transform.get()); - - d1_dz = -d2z / (dz * dz); - } -#else - d1_dz = 0; -#endif - } - communicate(d1_dx, d1_dy, d1_dz); + correctionForNonUniformMeshes(force_interpolate_from_centre); if (location == CELL_CENTRE && recalculate_staggered) { // Re-calculate interpolated Coordinates at staggered locations localmesh->recalculateStaggeredCoordinates(); } - // Invalidate and recalculate cached variables zlength_cache.reset(); Grad2_par2_DDY_invSgCache.clear(); invSgCache.reset(); - - return 0; } -int Coordinates::calcCovariant(const std::string& region) { - TRACE("Coordinates::calcCovariant"); - - // Make sure metric elements are allocated - g_11.allocate(); - g_22.allocate(); - g_33.allocate(); - g_12.allocate(); - g_13.allocate(); - g_23.allocate(); - - g_11.setLocation(location); - g_22.setLocation(location); - g_33.setLocation(location); - g_12.setLocation(location); - g_13.setLocation(location); - g_23.setLocation(location); - - // Perform inversion of g^{ij} to get g_{ij} - // NOTE: Currently this bit assumes that metric terms are Field2D objects - - auto a = Matrix(3, 3); - - BOUT_FOR_SERIAL(i, g11.getRegion(region)) { - a(0, 0) = g11[i]; - a(1, 1) = g22[i]; - a(2, 2) = g33[i]; - - a(0, 1) = a(1, 0) = g12[i]; - a(1, 2) = a(2, 1) = g23[i]; - a(0, 2) = a(2, 0) = g13[i]; - - if (invert3x3(a)) { - output_error.write("\tERROR: metric tensor is singular at ({:d}, {:d})\n", i.x(), - i.y()); - return 1; - } - - g_11[i] = a(0, 0); - g_22[i] = a(1, 1); - g_33[i] = a(2, 2); - - g_12[i] = a(0, 1); - g_13[i] = a(0, 2); - g_23[i] = a(1, 2); - } - - BoutReal maxerr; - maxerr = BOUTMAX(max(abs((g_11 * g11 + g_12 * g12 + g_13 * g13) - 1)), - max(abs((g_12 * g12 + g_22 * g22 + g_23 * g23) - 1)), - max(abs((g_13 * g13 + g_23 * g23 + g_33 * g33) - 1))); - - output_info.write("\tLocal maximum error in diagonal inversion is {:e}\n", maxerr); - - maxerr = BOUTMAX(max(abs(g_11 * g12 + g_12 * g22 + g_13 * g23)), - max(abs(g_11 * g13 + g_12 * g23 + g_13 * g33)), - max(abs(g_12 * g13 + g_22 * g23 + g_23 * g33))); - - output_info.write("\tLocal maximum error in off-diagonal inversion is {:e}\n", maxerr); +void Coordinates::correctionForNonUniformMeshes(bool force_interpolate_from_centre) { + OPTION(Options::getRoot(), non_uniform_, true); - return 0; -} - -int Coordinates::calcContravariant(const std::string& region) { - TRACE("Coordinates::calcContravariant"); + FieldMetric d2x(localmesh); + FieldMetric d2y(localmesh); + FieldMetric d2z(localmesh); // d^2 x / d i^2 - // Make sure metric elements are allocated - g11.allocate(); - g22.allocate(); - g33.allocate(); - g12.allocate(); - g13.allocate(); - g23.allocate(); + // Read correction for non-uniform meshes + std::string const suffix = getLocationSuffix(location); - // Perform inversion of g_{ij} to get g^{ij} - // NOTE: Currently this bit assumes that metric terms are Field2D objects + auto extrapolate_x = true; + auto extrapolate_y = true; + if (location == CELL_CENTRE + or (!force_interpolate_from_centre and localmesh->sourceHasVar("dx" + suffix))) { + extrapolate_x = not localmesh->sourceHasXBoundaryGuards(); + extrapolate_y = not localmesh->sourceHasYBoundaryGuards(); + } - auto a = Matrix(3, 3); + if (localmesh->get(d2x, "d2x" + suffix, 0.0, false, location) != 0) { + output_warn.write("\tWARNING: differencing quantity 'd2x' not found. " + "Calculating from dx\n"); + d1_dx_ = bout::derivatives::index::DDX(1. / dx()); // d/di(1/dx) - BOUT_FOR_SERIAL(i, g_11.getRegion(region)) { - a(0, 0) = g_11[i]; - a(1, 1) = g_22[i]; - a(2, 2) = g_33[i]; + communicate(d1_dx_); + d1_dx_ = + interpolateAndExtrapolate(d1_dx_, location, true, true, true, transform.get()); + } else { + d2x.setLocation(location); + // set boundary cells if necessary + d2x = interpolateAndExtrapolate(d2x, location, extrapolate_x, extrapolate_y, false, + transform.get()); - a(0, 1) = a(1, 0) = g_12[i]; - a(1, 2) = a(2, 1) = g_23[i]; - a(0, 2) = a(2, 0) = g_13[i]; + d1_dx_ = -d2x / (dx() * dx()); + } - if (invert3x3(a)) { - output_error.write("\tERROR: metric tensor is singular at ({:d}, {:d})\n", i.x(), - i.y()); - return 1; - } + if (localmesh->get(d2y, "d2y" + suffix, 0.0, false, location) != 0) { + output_warn.write("\tWARNING: differencing quantity 'd2y' not found. " + "Calculating from dy\n"); + d1_dy_ = bout::derivatives::index::DDY(1. / dy()); // d/di(1/dy) - g11[i] = a(0, 0); - g22[i] = a(1, 1); - g33[i] = a(2, 2); + communicate(d1_dy_); + d1_dy_ = + interpolateAndExtrapolate(d1_dy_, location, true, true, true, transform.get()); + } else { + d2y.setLocation(location); + // set boundary cells if necessary + d2y = interpolateAndExtrapolate(d2y, location, extrapolate_x, extrapolate_y, false, + transform.get()); - g12[i] = a(0, 1); - g13[i] = a(0, 2); - g23[i] = a(1, 2); + d1_dy_ = -d2y / (dy() * dy()); } - BoutReal maxerr; - maxerr = BOUTMAX(max(abs((g_11 * g11 + g_12 * g12 + g_13 * g13) - 1)), - max(abs((g_12 * g12 + g_22 * g22 + g_23 * g23) - 1)), - max(abs((g_13 * g13 + g_23 * g23 + g_33 * g33) - 1))); - - output_info.write("\tMaximum error in diagonal inversion is {:e}\n", maxerr); +#if BOUT_USE_METRIC_3D + if (localmesh->get(d2z, "d2z" + suffix, 0.0, false, location)) { + output_warn.write("\tWARNING: differencing quantity 'd2z' not found. " + "Calculating from dz\n"); + d1_dz_ = bout::derivatives::index::DDZ(1. / dz()); + communicate(d1_dz_); + d1_dz_ = + interpolateAndExtrapolate(d1_dz_, location, true, true, true, transform.get()); + } else { + d2z.setLocation(location); + // set boundary cells if necessary + d2z = interpolateAndExtrapolate(d2z, location, extrapolate_x, extrapolate_y, false, + transform.get()); - maxerr = BOUTMAX(max(abs(g_11 * g12 + g_12 * g22 + g_13 * g23)), - max(abs(g_11 * g13 + g_12 * g23 + g_13 * g33)), - max(abs(g_12 * g13 + g_22 * g23 + g_23 * g33))); + d1_dz_ = -d2z / (dz() * dz()); + } +#else + d1_dz_ = 0; +#endif - output_info.write("\tMaximum error in off-diagonal inversion is {:e}\n", maxerr); - return 0; + localmesh->communicate(d1_dx_, d1_dy_, d1_dz_); } -int Coordinates::jacobian() { - TRACE("Coordinates::jacobian"); - // calculate Jacobian using g^-1 = det[g^ij], J = sqrt(g) - - const bool extrapolate_x = not localmesh->sourceHasXBoundaryGuards(); - const bool extrapolate_y = not localmesh->sourceHasYBoundaryGuards(); - - auto g = g11 * g22 * g33 + 2.0 * g12 * g13 * g23 - g11 * g23 * g23 - g22 * g13 * g13 - - g33 * g12 * g12; +MetricTensor::FieldMetric Coordinates::recalculateJacobian() const { - // Check that g is positive - bout::checkPositive(g, "The determinant of g^ij", "RGN_NOBNDRY"); - - J = 1. / sqrt(g); - // More robust to extrapolate derived quantities directly, rather than - // deriving from extrapolated covariant metric components - J = interpolateAndExtrapolate(J, location, extrapolate_x, extrapolate_y, false, - transform.get()); - - Bxy = sqrt(g_22) / J; - Bxy = interpolateAndExtrapolate(Bxy, location, extrapolate_x, extrapolate_y, false, - transform.get()); - - return 0; + TRACE("Coordinates::jacobian"); + try { + // calculate Jacobian using g^-1 = det[g^ij], J = sqrt(g) + auto g_matrix = g11() * g22() * g33() + 2.0 * g12() * g13() * g23() + - g11() * g23() * g23() - g22() * g13() * g13() + - g33() * g12() * g12(); + + bout::checkPositive(g_matrix, "The determinant of g^ij", "RGN_NOBNDRY"); + + return 1. / sqrt(g_matrix); + } catch (const BoutException& e) { + output_error.write("\tError in jacobian call\n"); + throw e; + } } -namespace { -// Utility function for fixing up guard cells of zShift -void fixZShiftGuards(Field2D& zShift) { - auto localmesh = zShift.getMesh(); - - // extrapolate into boundary guard cells if necessary - zShift = interpolateAndExtrapolate(zShift, zShift.getLocation(), - not localmesh->sourceHasXBoundaryGuards(), - not localmesh->sourceHasYBoundaryGuards(), false); - - // make sure zShift has been communicated - communicate(zShift); - - // Correct guard cells for discontinuity of zShift at poloidal branch cut - for (int x = 0; x < localmesh->LocalNx; x++) { - const auto lower = localmesh->hasBranchCutLower(x); - if (lower.first) { - for (int y = 0; y < localmesh->ystart; y++) { - zShift(x, y) -= lower.second; - } - } - const auto upper = localmesh->hasBranchCutUpper(x); - if (upper.first) { - for (int y = localmesh->yend + 1; y < localmesh->LocalNy; y++) { - zShift(x, y) += upper.second; - } - } - } +MetricTensor::FieldMetric Coordinates::recalculateBxy() const { + return sqrt(g_22()) / J(); } -} // namespace -void Coordinates::setParallelTransform(Options* options) { +void Coordinates::setParallelTransform(Options* mesh_options) { - auto ptoptions = options->getSection("paralleltransform"); + auto* ptoptions = mesh_options->getSection("paralleltransform"); std::string ptstr; ptoptions->get("type", ptstr, "identity"); @@ -1398,20 +922,22 @@ void Coordinates::setParallelTransform(Options* options) { // Identity method i.e. no transform needed transform = bout::utils::make_unique(*localmesh, ptoptions); + return; + } - } else if (ptstr == "shifted" or ptstr == "shiftedinterp") { + if (ptstr == "shifted" or ptstr == "shiftedinterp") { // Shifted metric method Field2D zShift{localmesh}; // Read the zShift angle from the mesh - std::string suffix = getLocationSuffix(location); + std::string const suffix = getLocationSuffix(location); if (localmesh->sourceHasVar("dx" + suffix)) { // Grid file has variables at this location, so should be able to read checkStaggeredGet(localmesh, "zShift", suffix); - if (localmesh->get(zShift, "zShift" + suffix, 0.0, false, location)) { + if (localmesh->get(zShift, "zShift" + suffix, 0.0, false, location) != 0) { // No zShift variable. Try qinty in BOUT grid files - if (localmesh->get(zShift, "qinty" + suffix, 0.0, false, location)) { + if (localmesh->get(zShift, "qinty" + suffix, 0.0, false, location) != 0) { // Failed to find either variable, cannot use ShiftedMetric throw BoutException("Could not read zShift" + suffix + " from grid file"); } @@ -1423,9 +949,9 @@ void Coordinates::setParallelTransform(Options* options) { "file."); } Field2D zShift_centre; - if (localmesh->get(zShift_centre, "zShift", 0.0, false)) { + if (localmesh->get(zShift_centre, "zShift", 0.0, false) != 0) { // No zShift variable. Try qinty in BOUT grid files - if (localmesh->get(zShift_centre, "qinty", 0.0, false)) { + if (localmesh->get(zShift_centre, "qinty", 0.0, false) != 0) { // Failed to find either variable, cannot use ShiftedMetric throw BoutException("Could not read zShift from grid file"); } @@ -1442,12 +968,17 @@ void Coordinates::setParallelTransform(Options* options) { if (ptstr == "shifted") { transform = bout::utils::make_unique(*localmesh, location, zShift, getUniform(zlength())); - } else if (ptstr == "shiftedinterp") { + } + + if (ptstr == "shiftedinterp") { transform = bout::utils::make_unique( *localmesh, location, zShift, getUniform(zlength())); } - } else if (ptstr == "fci") { + return; + } + + if (ptstr == "fci") { if (location != CELL_CENTRE) { throw BoutException("FCITransform is not available on staggered grids."); @@ -1455,13 +986,13 @@ void Coordinates::setParallelTransform(Options* options) { // Flux Coordinate Independent method const bool fci_zperiodic = (*ptoptions)["z_periodic"].withDefault(true); - transform = - bout::utils::make_unique(*localmesh, dy, fci_zperiodic, ptoptions); - - } else { - throw BoutException(_("Unrecognised paralleltransform option.\n" - "Valid choices are 'identity', 'shifted', 'fci'")); + transform = bout::utils::make_unique(*localmesh, dy(), fci_zperiodic, + ptoptions); + return; } + + throw BoutException(_("Unrecognised paralleltransform option.\n" + "Valid choices are 'identity', 'shifted', 'fci'")); } /******************************************************************************* @@ -1471,19 +1002,19 @@ void Coordinates::setParallelTransform(Options* options) { Coordinates::FieldMetric Coordinates::DDX(const Field2D& f, CELL_LOC loc, const std::string& method, - const std::string& region) { + const std::string& region) const { ASSERT1(location == loc || loc == CELL_DEFAULT); - return bout::derivatives::index::DDX(f, loc, method, region) / dx; + return bout::derivatives::index::DDX(f, loc, method, region) / dx(); } Field3D Coordinates::DDX(const Field3D& f, CELL_LOC outloc, const std::string& method, - const std::string& region) { + const std::string& region) const { auto result = bout::derivatives::index::DDX(f, outloc, method, region); - result /= dx; + result /= dx(); if (f.getMesh()->IncIntShear) { // Using BOUT-06 style shifting - result += IntShiftTorsion * DDZ(f, outloc, method, region); + result += IntShiftTorsion() * DDZ(f, outloc, method, region); } return result; @@ -1493,12 +1024,13 @@ Coordinates::FieldMetric Coordinates::DDY(const Field2D& f, CELL_LOC loc, const std::string& method, const std::string& region) const { ASSERT1(location == loc || loc == CELL_DEFAULT); - return bout::derivatives::index::DDY(f, loc, method, region) / dy; + return bout::derivatives::index::DDY(f, loc, method, region) / dy(); } Field3D Coordinates::DDY(const Field3D& f, CELL_LOC outloc, const std::string& method, const std::string& region) const { #if BOUT_USE_METRIC_3D + ASSERT0(transform != nullptr); if (!f.hasParallelSlices() and !transform->canToFromFieldAligned()) { Field3D f_parallel = f; transform->calcParallelSlices(f_parallel); @@ -1506,12 +1038,12 @@ Field3D Coordinates::DDY(const Field3D& f, CELL_LOC outloc, const std::string& m return bout::derivatives::index::DDY(f_parallel, outloc, method, region); } #endif - return bout::derivatives::index::DDY(f, outloc, method, region) / dy; + return bout::derivatives::index::DDY(f, outloc, method, region) / dy(); }; Coordinates::FieldMetric Coordinates::DDZ(const Field2D& f, CELL_LOC loc, const std::string& UNUSED(method), - const std::string& UNUSED(region)) { + const std::string& UNUSED(region)) const { ASSERT1(location == loc || loc == CELL_DEFAULT); ASSERT1(f.getMesh() == localmesh); if (loc == CELL_DEFAULT) { @@ -1520,16 +1052,15 @@ Coordinates::FieldMetric Coordinates::DDZ(const Field2D& f, CELL_LOC loc, return zeroFrom(f).setLocation(loc); } Field3D Coordinates::DDZ(const Field3D& f, CELL_LOC outloc, const std::string& method, - const std::string& region) { - return bout::derivatives::index::DDZ(f, outloc, method, region) / dz; + const std::string& region) const { + return bout::derivatives::index::DDZ(f, outloc, method, region) / dz(); }; ///////////////////////////////////////////////////////// // Parallel gradient -Coordinates::FieldMetric Coordinates::Grad_par(const Field2D& var, - [[maybe_unused]] CELL_LOC outloc, - const std::string& UNUSED(method)) { +FieldMetric Coordinates::Grad_par(const Field2D& var, [[maybe_unused]] CELL_LOC outloc, + const std::string& UNUSED(method)) { TRACE("Coordinates::Grad_par( Field2D )"); ASSERT1(location == outloc || (outloc == CELL_DEFAULT && location == var.getLocation())); @@ -1549,9 +1080,9 @@ Field3D Coordinates::Grad_par(const Field3D& var, CELL_LOC outloc, // Vpar_Grad_par // vparallel times the parallel derivative along unperturbed B-field -Coordinates::FieldMetric Coordinates::Vpar_Grad_par(const Field2D& v, const Field2D& f, - [[maybe_unused]] CELL_LOC outloc, - const std::string& UNUSED(method)) { +FieldMetric Coordinates::Vpar_Grad_par(const Field2D& v, const Field2D& f, + [[maybe_unused]] CELL_LOC outloc, + const std::string& UNUSED(method)) { ASSERT1(location == outloc || (outloc == CELL_DEFAULT && location == f.getLocation())); return VDDY(v, f) * invSg(); @@ -1574,9 +1105,9 @@ Coordinates::FieldMetric Coordinates::Div_par(const Field2D& f, CELL_LOC outloc, // Need Bxy at location of f, which might be different from location of this // Coordinates object - auto Bxy_floc = f.getCoordinates()->Bxy; + auto Bxy_floc = f.getCoordinates()->Bxy(); - return Bxy * Grad_par(f / Bxy_floc, outloc, method); + return Bxy() * Grad_par(f / Bxy_floc, outloc, method); } Field3D Coordinates::Div_par(const Field3D& f, CELL_LOC outloc, @@ -1586,12 +1117,12 @@ Field3D Coordinates::Div_par(const Field3D& f, CELL_LOC outloc, // Need Bxy at location of f, which might be different from location of this // Coordinates object - auto Bxy_floc = f.getCoordinates()->Bxy; + auto Bxy_floc = f.getCoordinates()->Bxy(); if (!f.hasParallelSlices()) { // No yup/ydown fields. The Grad_par operator will // shift to field aligned coordinates - return Bxy * Grad_par(f / Bxy_floc, outloc, method); + return Bxy() * Grad_par(f / Bxy_floc, outloc, method); } // Need to modify yup and ydown fields @@ -1601,7 +1132,7 @@ Field3D Coordinates::Div_par(const Field3D& f, CELL_LOC outloc, f_B.yup(i) = f.yup(i) / Bxy_floc.yup(i); f_B.ydown(i) = f.ydown(i) / Bxy_floc.ydown(i); } - return Bxy * Grad_par(f_B, outloc, method); + return Bxy() * Grad_par(f_B, outloc, method); } ///////////////////////////////////////////////////////// @@ -1614,7 +1145,7 @@ Coordinates::FieldMetric Coordinates::Grad2_par2(const Field2D& f, CELL_LOC outl ASSERT1(location == outloc || (outloc == CELL_DEFAULT && location == f.getLocation())); auto result = Grad2_par2_DDY_invSg(outloc, method) * DDY(f, outloc, method) - + D2DY2(f, outloc, method) / g_22; + + D2DY2(f, outloc, method) / g_22(); return result; } @@ -1629,7 +1160,7 @@ Field3D Coordinates::Grad2_par2(const Field3D& f, CELL_LOC outloc, Field3D result = ::DDY(f, outloc, method); - Field3D r2 = D2DY2(f, outloc, method) / g_22; + Field3D r2 = D2DY2(f, outloc, method) / g_22(); result = Grad2_par2_DDY_invSg(outloc, method) * result + r2; @@ -1648,9 +1179,7 @@ Coordinates::FieldMetric Coordinates::Delp2(const Field2D& f, CELL_LOC outloc, TRACE("Coordinates::Delp2( Field2D )"); ASSERT1(location == outloc || outloc == CELL_DEFAULT); - auto result = G1 * DDX(f, outloc) + g11 * D2DX2(f, outloc); - - return result; + return G1() * DDX(f, outloc) + g11() * D2DX2(f, outloc); } Field3D Coordinates::Delp2(const Field3D& f, CELL_LOC outloc, bool useFFT) { @@ -1667,7 +1196,7 @@ Field3D Coordinates::Delp2(const Field3D& f, CELL_LOC outloc, bool useFFT) { // copy mesh, location, etc return f * 0; } - ASSERT2(localmesh->xstart > 0); // Need at least one guard cell + ASSERT2(localmesh->xstart > 0); // Need at least one guard cell; Field3D result{emptyFrom(f).setLocation(outloc)}; @@ -1710,9 +1239,10 @@ Field3D Coordinates::Delp2(const Field3D& f, CELL_LOC outloc, bool useFFT) { } } } else { - result = G1 * ::DDX(f, outloc) + G3 * ::DDZ(f, outloc) + g11 * ::D2DX2(f, outloc) - + g33 * ::D2DZ2(f, outloc) + 2 * g13 * ::D2DXDZ(f, outloc); - }; + result = G1() * ::DDX(f, outloc) + G3() * ::DDZ(f, outloc) + + g11() * ::D2DX2(f, outloc) + g33() * ::D2DZ2(f, outloc) + + 2 * g13() * ::D2DXDZ(f, outloc); + } ASSERT2(result.getLocation() == outloc); @@ -1737,11 +1267,11 @@ FieldPerp Coordinates::Delp2(const FieldPerp& f, CELL_LOC outloc, bool useFFT) { FieldPerp result{emptyFrom(f).setLocation(outloc)}; - int jy = f.getIndex(); + int const jy = f.getIndex(); result.setIndex(jy); if (useFFT) { - int ncz = localmesh->LocalNz; + int const ncz = localmesh->LocalNz; // Allocate memory auto ft = Matrix(localmesh->LocalNx, ncz / 2 + 1); @@ -1784,12 +1314,13 @@ FieldPerp Coordinates::Delp2(const FieldPerp& f, CELL_LOC outloc, bool useFFT) { Coordinates::FieldMetric Coordinates::Laplace_par(const Field2D& f, CELL_LOC outloc) { ASSERT1(location == outloc || outloc == CELL_DEFAULT); - return D2DY2(f, outloc) / g_22 + DDY(J / g_22, outloc) * DDY(f, outloc) / J; + + return D2DY2(f, outloc) / g_22() + DDY(J() / g_22(), outloc) * DDY(f, outloc) / J(); } Field3D Coordinates::Laplace_par(const Field3D& f, CELL_LOC outloc) { ASSERT1(location == outloc || outloc == CELL_DEFAULT); - return D2DY2(f, outloc) / g_22 + DDY(J / g_22, outloc) * ::DDY(f, outloc) / J; + return D2DY2(f, outloc) / g_22() + ::DDY(J() / g_22(), outloc) * ::DDY(f, outloc) / J(); } // Full Laplacian operator on scalar field @@ -1800,13 +1331,11 @@ Coordinates::FieldMetric Coordinates::Laplace(const Field2D& f, CELL_LOC outloc, TRACE("Coordinates::Laplace( Field2D )"); ASSERT1(location == outloc || outloc == CELL_DEFAULT); - auto result = G1 * DDX(f, outloc) + G2 * DDY(f, outloc) + g11 * D2DX2(f, outloc) - + g22 * D2DY2(f, outloc) - + 2.0 * g12 - * D2DXDY(f, outloc, "DEFAULT", "RGN_NOBNDRY", - dfdy_boundary_conditions, dfdy_dy_region); - - return result; + return G1() * DDX(f, outloc) + G2() * DDY(f, outloc) + g11() * D2DX2(f, outloc) + + g22() * D2DY2(f, outloc) + + 2.0 * g12() + * ::D2DXDY(f, outloc, "DEFAULT", "RGN_NOBNDRY", dfdy_boundary_conditions, + dfdy_dy_region); } Field3D Coordinates::Laplace(const Field3D& f, CELL_LOC outloc, @@ -1815,22 +1344,20 @@ Field3D Coordinates::Laplace(const Field3D& f, CELL_LOC outloc, TRACE("Coordinates::Laplace( Field3D )"); ASSERT1(location == outloc || outloc == CELL_DEFAULT); - Field3D result = G1 * ::DDX(f, outloc) + G2 * ::DDY(f, outloc) + G3 * ::DDZ(f, outloc) - + g11 * D2DX2(f, outloc) + g22 * D2DY2(f, outloc) - + g33 * D2DZ2(f, outloc) - + 2.0 - * (g12 - * D2DXDY(f, outloc, "DEFAULT", "RGN_NOBNDRY", - dfdy_boundary_conditions, dfdy_dy_region) - + g13 * D2DXDZ(f, outloc) + g23 * D2DYDZ(f, outloc)); - - return result; + return G1() * ::DDX(f, outloc) + G2() * ::DDY(f, outloc) + G3() * ::DDZ(f, outloc) + + g11() * ::D2DX2(f, outloc) + g22() * ::D2DY2(f, outloc) + + g33() * ::D2DZ2(f, outloc) + + 2.0 + * (g12() + * D2DXDY(f, outloc, "DEFAULT", "RGN_NOBNDRY", + dfdy_boundary_conditions, dfdy_dy_region) + + g13() * ::D2DXDZ(f, outloc) + g23() * ::D2DYDZ(f, outloc)); } // Full perpendicular Laplacian, in form of inverse of Laplacian operator in LaplaceXY // solver Field2D Coordinates::Laplace_perpXY([[maybe_unused]] const Field2D& A, - [[maybe_unused]] const Field2D& f) { + [[maybe_unused]] const Field2D& f) const { TRACE("Coordinates::Laplace_perpXY( Field2D )"); #if not(BOUT_USE_METRIC_3D) Field2D result; @@ -1841,45 +1368,45 @@ Field2D Coordinates::Laplace_perpXY([[maybe_unused]] const Field2D& A, // outer x boundary const auto outer_x_avg = [&i](const auto& f) { return 0.5 * (f[i] + f[i.xp()]); }; const BoutReal outer_x_A = outer_x_avg(A); - const BoutReal outer_x_J = outer_x_avg(J); - const BoutReal outer_x_g11 = outer_x_avg(g11); - const BoutReal outer_x_dx = outer_x_avg(dx); + const BoutReal outer_x_J = outer_x_avg(J()); + const BoutReal outer_x_g11 = outer_x_avg(g11()); + const BoutReal outer_x_dx = outer_x_avg(dx()); const BoutReal outer_x_value = - outer_x_A * outer_x_J * outer_x_g11 / (J[i] * outer_x_dx * dx[i]); + outer_x_A * outer_x_J * outer_x_g11 / (J()[i] * outer_x_dx * dx()[i]); result[i] += outer_x_value * (f[i.xp()] - f[i]); // inner x boundary const auto inner_x_avg = [&i](const auto& f) { return 0.5 * (f[i] + f[i.xm()]); }; const BoutReal inner_x_A = inner_x_avg(A); - const BoutReal inner_x_J = inner_x_avg(J); - const BoutReal inner_x_g11 = inner_x_avg(g11); - const BoutReal inner_x_dx = inner_x_avg(dx); + const BoutReal inner_x_J = inner_x_avg(J()); + const BoutReal inner_x_g11 = inner_x_avg(g11()); + const BoutReal inner_x_dx = inner_x_avg(dx()); const BoutReal inner_x_value = - inner_x_A * inner_x_J * inner_x_g11 / (J[i] * inner_x_dx * dx[i]); + inner_x_A * inner_x_J * inner_x_g11 / (J()[i] * inner_x_dx * dx()[i]); result[i] += inner_x_value * (f[i.xm()] - f[i]); // upper y boundary const auto upper_y_avg = [&i](const auto& f) { return 0.5 * (f[i] + f[i.yp()]); }; const BoutReal upper_y_A = upper_y_avg(A); - const BoutReal upper_y_J = upper_y_avg(J); - const BoutReal upper_y_g_22 = upper_y_avg(g_22); - const BoutReal upper_y_g23 = upper_y_avg(g23); - const BoutReal upper_y_g_23 = upper_y_avg(g_23); - const BoutReal upper_y_dy = upper_y_avg(dy); + const BoutReal upper_y_J = upper_y_avg(J()); + const BoutReal upper_y_g_22 = upper_y_avg(g_22()); + const BoutReal upper_y_g23 = upper_y_avg(g23()); + const BoutReal upper_y_g_23 = upper_y_avg(g_23()); + const BoutReal upper_y_dy = upper_y_avg(dy()); const BoutReal upper_y_value = -upper_y_A * upper_y_J * upper_y_g23 * upper_y_g_23 - / (upper_y_g_22 * J[i] * upper_y_dy * dy[i]); + / (upper_y_g_22 * J()[i] * upper_y_dy * dy()[i]); result[i] += upper_y_value * (f[i.yp()] - f[i]); // lower y boundary const auto lower_y_avg = [&i](const auto& f) { return 0.5 * (f[i] + f[i.ym()]); }; const BoutReal lower_y_A = lower_y_avg(A); - const BoutReal lower_y_J = lower_y_avg(J); - const BoutReal lower_y_g_22 = lower_y_avg(g_22); - const BoutReal lower_y_g23 = lower_y_avg(g23); - const BoutReal lower_y_g_23 = lower_y_avg(g_23); - const BoutReal lower_y_dy = lower_y_avg(dy); + const BoutReal lower_y_J = lower_y_avg(J()); + const BoutReal lower_y_g_22 = lower_y_avg(g_22()); + const BoutReal lower_y_g23 = lower_y_avg(g23()); + const BoutReal lower_y_g_23 = lower_y_avg(g_23()); + const BoutReal lower_y_dy = lower_y_avg(dy()); const BoutReal lower_y_value = -lower_y_A * lower_y_J * lower_y_g23 * lower_y_g_23 - / (lower_y_g_22 * J[i] * lower_y_dy * dy[i]); + / (lower_y_g_22 * J()[i] * lower_y_dy * dy()[i]); result[i] += lower_y_value * (f[i.ym()] - f[i]); } @@ -1889,10 +1416,43 @@ Field2D Coordinates::Laplace_perpXY([[maybe_unused]] const Field2D& A, #endif } +ChristoffelSymbols& Coordinates::christoffel_symbols() { + if (christoffel_symbols_cache == nullptr) { + christoffel_symbols_cache = std::make_unique(*this); + // Set boundary guard cells of Christoffel symbol terms + // Ideally, when location is staggered, we would set the upper/outer boundary point + // correctly rather than by extrapolating here: e.g. if location==CELL_YLOW and we are + // at the upper y-boundary the x- and z-derivatives at yend+1 at the boundary can be + // calculated because the guard cells are available, while the y-derivative could be + // calculated from the CELL_CENTRE metric components (which have guard cells available + // past the boundary location). This would avoid the problem that the y-boundary on the + // CELL_YLOW grid is at a 'guard cell' location (yend+1). + // However, the above would require lots of special handling, so just extrapolate for + // now. + + christoffel_symbols_cache->map([this](const FieldMetric& component) { + return interpolateAndExtrapolate(component, location, true, true, false, + transform.get()); + }); + } + return *christoffel_symbols_cache; +} + +GValues& Coordinates::g_values() const { + if (g_values_cache == nullptr) { + g_values_cache = std::make_unique(*this); + g_values_cache->map([this](const FieldMetric& component) { + return interpolateAndExtrapolate(component, location, true, true, true, + transform.get()); + }); + } + return *g_values_cache; +} + const Coordinates::FieldMetric& Coordinates::invSg() const { if (invSgCache == nullptr) { auto ptr = std::make_unique(); - (*ptr) = 1.0 / sqrt(g_22); + (*ptr) = 1.0 / sqrt(g_22()); invSgCache = std::move(ptr); } return *invSgCache; @@ -1900,6 +1460,7 @@ const Coordinates::FieldMetric& Coordinates::invSg() const { const Coordinates::FieldMetric& Coordinates::Grad2_par2_DDY_invSg(CELL_LOC outloc, const std::string& method) const { + if (auto search = Grad2_par2_DDY_invSgCache.find(method); search != Grad2_par2_DDY_invSgCache.end()) { return *search->second; @@ -1917,106 +1478,54 @@ Coordinates::Grad2_par2_DDY_invSg(CELL_LOC outloc, const std::string& method) co return *Grad2_par2_DDY_invSgCache[method]; } -void Coordinates::checkCovariant() { - // Diagonal metric components should be finite - bout::checkFinite(g_11, "g_11", "RGN_NOCORNERS"); - bout::checkFinite(g_22, "g_22", "RGN_NOCORNERS"); - bout::checkFinite(g_33, "g_33", "RGN_NOCORNERS"); - if (g_11.hasParallelSlices() && &g_11.ynext(1) != &g_11) { - for (int dy = 1; dy <= localmesh->ystart; ++dy) { - for (const auto sign : {1, -1}) { - bout::checkFinite(g_11.ynext(sign * dy), "g_11.ynext", - fmt::format("RGN_YPAR_{:+d}", sign * dy)); - bout::checkFinite(g_22.ynext(sign * dy), "g_22.ynext", - fmt::format("RGN_YPAR_{:+d}", sign * dy)); - bout::checkFinite(g_33.ynext(sign * dy), "g_33.ynext", - fmt::format("RGN_YPAR_{:+d}", sign * dy)); - } - } - } - // Diagonal metric components should be positive - bout::checkPositive(g_11, "g_11", "RGN_NOCORNERS"); - bout::checkPositive(g_22, "g_22", "RGN_NOCORNERS"); - bout::checkPositive(g_33, "g_33", "RGN_NOCORNERS"); - if (g_11.hasParallelSlices() && &g_11.ynext(1) != &g_11) { - for (int dy = 1; dy <= localmesh->ystart; ++dy) { - for (const auto sign : {1, -1}) { - bout::checkPositive(g_11.ynext(sign * dy), "g_11.ynext", - fmt::format("RGN_YPAR_{:+d}", sign * dy)); - bout::checkPositive(g_22.ynext(sign * dy), "g_22.ynext", - fmt::format("RGN_YPAR_{:+d}", sign * dy)); - bout::checkPositive(g_33.ynext(sign * dy), "g_33.ynext", - fmt::format("RGN_YPAR_{:+d}", sign * dy)); - } - } - } +void Coordinates::checkCovariant() { covariantMetricTensor.check(localmesh->ystart); } - // Off-diagonal metric components should be finite - bout::checkFinite(g_12, "g_12", "RGN_NOCORNERS"); - bout::checkFinite(g_13, "g_13", "RGN_NOCORNERS"); - bout::checkFinite(g_23, "g_23", "RGN_NOCORNERS"); - if (g_23.hasParallelSlices() && &g_23.ynext(1) != &g_23) { - for (int dy = 1; dy <= localmesh->ystart; ++dy) { - for (const auto sign : {1, -1}) { - bout::checkFinite(g_12.ynext(sign * dy), "g_12.ynext", - fmt::format("RGN_YPAR_{:+d}", sign * dy)); - bout::checkFinite(g_13.ynext(sign * dy), "g_13.ynext", - fmt::format("RGN_YPAR_{:+d}", sign * dy)); - bout::checkFinite(g_23.ynext(sign * dy), "g_23.ynext", - fmt::format("RGN_YPAR_{:+d}", sign * dy)); - } - } - } +void Coordinates::checkContravariant() { + contravariantMetricTensor.check(localmesh->ystart); } -void Coordinates::checkContravariant() { - // Diagonal metric components should be finite - bout::checkFinite(g11, "g11", "RGN_NOCORNERS"); - bout::checkFinite(g22, "g22", "RGN_NOCORNERS"); - bout::checkFinite(g33, "g33", "RGN_NOCORNERS"); - if (g11.hasParallelSlices() && &g11.ynext(1) != &g11) { - for (int dy = 1; dy <= localmesh->ystart; ++dy) { - for (const auto sign : {1, -1}) { - bout::checkFinite(g11.ynext(sign * dy), "g11.ynext", - fmt::format("RGN_YPAR_{:+d}", sign * dy)); - bout::checkFinite(g22.ynext(sign * dy), "g22.ynext", - fmt::format("RGN_YPAR_{:+d}", sign * dy)); - bout::checkFinite(g33.ynext(sign * dy), "g33.ynext", - fmt::format("RGN_YPAR_{:+d}", sign * dy)); - } - } - } - // Diagonal metric components should be positive - bout::checkPositive(g11, "g11", "RGN_NOCORNERS"); - bout::checkPositive(g22, "g22", "RGN_NOCORNERS"); - bout::checkPositive(g33, "g33", "RGN_NOCORNERS"); - if (g11.hasParallelSlices() && &g11.ynext(1) != &g11) { - for (int dy = 1; dy <= localmesh->ystart; ++dy) { - for (const auto sign : {1, -1}) { - bout::checkPositive(g11.ynext(sign * dy), "g11.ynext", - fmt::format("RGN_YPAR_{:+d}", sign * dy)); - bout::checkPositive(g22.ynext(sign * dy), "g22.ynext", - fmt::format("RGN_YPAR_{:+d}", sign * dy)); - bout::checkPositive(g33.ynext(sign * dy), "g33.ynext", - fmt::format("RGN_YPAR_{:+d}", sign * dy)); - } - } +FieldMetric& Coordinates::J() const { + if (jacobian_cache == nullptr) { + jacobian_cache = std::make_unique(recalculateJacobian()); } + return *jacobian_cache; +} - // Off-diagonal metric components should be finite - bout::checkFinite(g12, "g12", "RGN_NOCORNERS"); - bout::checkFinite(g13, "g13", "RGN_NOCORNERS"); - bout::checkFinite(g23, "g23", "RGN_NOCORNERS"); - if (g23.hasParallelSlices() && &g23.ynext(1) != &g23) { - for (int dy = 1; dy <= localmesh->ystart; ++dy) { - for (const auto sign : {1, -1}) { - bout::checkFinite(g12.ynext(sign * dy), "g12.ynext", - fmt::format("RGN_YPAR_{:+d}", sign * dy)); - bout::checkFinite(g13.ynext(sign * dy), "g13.ynext", - fmt::format("RGN_YPAR_{:+d}", sign * dy)); - bout::checkFinite(g23.ynext(sign * dy), "g23.ynext", - fmt::format("RGN_YPAR_{:+d}", sign * dy)); - } - } - } +void Coordinates::setJ(const FieldMetric& J) { + bout::checkFinite(J, "J", "RGN_NOCORNERS"); + bout::checkPositive(J, "J", "RGN_NOCORNERS"); + + //TODO: Calculate J and check value is close + jacobian_cache = std::make_unique(J); + localmesh->communicate(*jacobian_cache); +} + +void Coordinates::setBxy(FieldMetric Bxy) { + //TODO: Calculate Bxy and check value is close + Bxy_ = std::move(Bxy); + localmesh->communicate(Bxy_); +} + +void Coordinates::setContravariantMetricTensor( + const ContravariantMetricTensor& metric_tensor, const std::string& region, + bool recalculate_staggered, bool force_interpolate_from_centre) { + contravariantMetricTensor.setMetricTensor(metric_tensor); + covariantMetricTensor.setMetricTensor(contravariantMetricTensor.inverse(region)); + recalculateAndReset(recalculate_staggered, force_interpolate_from_centre); +} + +void Coordinates::setCovariantMetricTensor(const CovariantMetricTensor& metric_tensor, + const std::string& region, + bool recalculate_staggered, + bool force_interpolate_from_centre) { + covariantMetricTensor.setMetricTensor(metric_tensor); + contravariantMetricTensor.setMetricTensor(covariantMetricTensor.inverse(region)); + recalculateAndReset(recalculate_staggered, force_interpolate_from_centre); +} + +void Coordinates::setMetricTensor( + const ContravariantMetricTensor& contravariant_metric_tensor, + const CovariantMetricTensor& covariant_metric_tensor) { + contravariantMetricTensor.setMetricTensor(contravariant_metric_tensor); + covariantMetricTensor.setMetricTensor(covariant_metric_tensor); } diff --git a/src/mesh/coordinates_accessor.cxx b/src/mesh/coordinates_accessor.cxx index aff546c2b0..b6df669066 100644 --- a/src/mesh/coordinates_accessor.cxx +++ b/src/mesh/coordinates_accessor.cxx @@ -1,6 +1,6 @@ #include "bout/coordinates_accessor.hxx" - #include "bout/mesh.hxx" +#include "bout/metric_tensor.hxx" #include @@ -17,7 +17,7 @@ CoordinatesAccessor::CoordinatesAccessor(const Coordinates* coords) { ASSERT0(coords != nullptr); // Size of the mesh in Z. Used to convert 3D -> 2D index - Mesh* mesh = coords->dx.getMesh(); + Mesh* mesh = coords->dx().getMesh(); mesh_nz = mesh->LocalNz; auto search = coords_store.find(coords); @@ -41,7 +41,7 @@ CoordinatesAccessor::CoordinatesAccessor(const Coordinates* coords) { // Copy data from Coordinates variable into data array // Uses the symbol to look up the corresponding Offset #define COPY_STRIPE1(symbol) \ - data[stripe_size * ind.ind + static_cast(Offset::symbol)] = coords->symbol[ind]; + data[stripe_size * ind.ind + static_cast(Offset::symbol)] = coords->symbol()[ind]; // Implement copy for each argument #define COPY_STRIPE(...) \ @@ -49,16 +49,15 @@ CoordinatesAccessor::CoordinatesAccessor(const Coordinates* coords) { // Iterate over all points in the field // Note this could be 2D or 3D, depending on FieldMetric type - for (const auto& ind : coords->dx.getRegion("RGN_ALL")) { + for (const auto& ind : coords->dx().getRegion("RGN_ALL")) { COPY_STRIPE(dx, dy, dz); COPY_STRIPE(d1_dx, d1_dy, d1_dz); COPY_STRIPE(J); - - data[stripe_size * ind.ind + static_cast(Offset::B)] = coords->Bxy[ind]; - data[stripe_size * ind.ind + static_cast(Offset::Byup)] = coords->Bxy.yup()[ind]; + data[stripe_size * ind.ind + static_cast(Offset::B)] = coords->Bxy()[ind]; + data[stripe_size * ind.ind + static_cast(Offset::Byup)] = + coords->Bxy().yup()[ind]; data[stripe_size * ind.ind + static_cast(Offset::Bydown)] = - coords->Bxy.ydown()[ind]; - + coords->Bxy().ydown()[ind]; COPY_STRIPE(G1, G3); COPY_STRIPE(g11, g12, g13, g22, g23, g33); COPY_STRIPE(g_11, g_12, g_13, g_22, g_23, g_33); diff --git a/src/mesh/difops.cxx b/src/mesh/difops.cxx index 2e25dfeedb..78c1ef35a1 100644 --- a/src/mesh/difops.cxx +++ b/src/mesh/difops.cxx @@ -84,7 +84,7 @@ Field3D Grad_parP(const Field3D& apar, const Field3D& f) { Field3D result{emptyFrom(f)}; - int ncz = mesh->LocalNz; + int const ncz = mesh->LocalNz; Coordinates* metric = apar.getCoordinates(); @@ -106,17 +106,17 @@ Field3D Grad_parP(const Field3D& apar, const Field3D& f) { for (int z = 0; z < ncz; z++) { BoutReal by = 1. / sqrt(metric->g_22(x, y, z)); // Z indices zm and zp - int zm = (z - 1 + ncz) % ncz; - int zp = (z + 1) % ncz; + int const zm = (z - 1 + ncz) % ncz; + int const zp = (z + 1) % ncz; // bx = -DDZ(apar) - BoutReal bx = (apar(x, y, zm) - apar(x, y, zp)) - / (0.5 * metric->dz(x, y, zm) + metric->dz(x, y, z) - + 0.5 * metric->dz(x, y, zp)); + BoutReal const bx = (apar(x, y, zm) - apar(x, y, zp)) + / (0.5 * metric->dz(x, y, zm) + metric->dz(x, y, z) + + 0.5 * metric->dz(x, y, zp)); // bz = DDX(f) - BoutReal bz = (apar(x + 1, y, z) - apar(x - 1, y, z)) - / (0.5 * metric->dx(x - 1, y, z) + metric->dx(x, y, z) - + 0.5 * metric->dx(x + 1, y, z)); + BoutReal const bz = (apar(x + 1, y, z) - apar(x - 1, y, z)) + / (0.5 * metric->dx(x - 1, y, z) + metric->dx(x, y, z) + + 0.5 * metric->dx(x + 1, y, z)); // Now calculate (bx*d/dx + by*d/dy + bz*d/dz) f @@ -251,19 +251,19 @@ Field3D Div_par(const Field3D& f, const Field3D& v) { for (int j = mesh->ystart; j <= mesh->yend; j++) { for (int k = mesh->zstart; k <= mesh->zend; k++) { // Value of f and v at left cell face - BoutReal fL = 0.5 * (f(i, j, k) + f.ydown()(i, j - 1, k)); - BoutReal vL = 0.5 * (v(i, j, k) + v.ydown()(i, j - 1, k)); + BoutReal const fL = 0.5 * (f(i, j, k) + f.ydown()(i, j - 1, k)); + BoutReal const vL = 0.5 * (v(i, j, k) + v.ydown()(i, j - 1, k)); - BoutReal fR = 0.5 * (f(i, j, k) + f.yup()(i, j + 1, k)); - BoutReal vR = 0.5 * (v(i, j, k) + v.yup()(i, j + 1, k)); + BoutReal const fR = 0.5 * (f(i, j, k) + f.yup()(i, j + 1, k)); + BoutReal const vR = 0.5 * (v(i, j, k) + v.yup()(i, j + 1, k)); // Calculate flux at right boundary (y+1/2) - BoutReal fluxRight = + BoutReal const fluxRight = fR * vR * (coord->J(i, j, k) + coord->J(i, j + 1, k)) / (sqrt(coord->g_22(i, j, k)) + sqrt(coord->g_22(i, j + 1, k))); // Calculate at left boundary (y-1/2) - BoutReal fluxLeft = + BoutReal const fluxLeft = fL * vL * (coord->J(i, j, k) + coord->J(i, j - 1, k)) / (sqrt(coord->g_22(i, j, k)) + sqrt(coord->g_22(i, j - 1, k))); @@ -282,10 +282,10 @@ Field3D Div_par_flux(const Field3D& v, const Field3D& f, CELL_LOC outloc, const std::string& method) { Coordinates* metric = f.getCoordinates(outloc); - auto Bxy_floc = f.getCoordinates()->Bxy; + auto Bxy_floc = f.getCoordinates()->Bxy(); if (!f.hasParallelSlices()) { - return metric->Bxy * FDDY(v, f / Bxy_floc, outloc, method) / sqrt(metric->g_22); + return metric->Bxy() * FDDY(v, f / Bxy_floc, outloc, method) / sqrt(metric->g_22()); } // Need to modify yup and ydown fields @@ -294,7 +294,7 @@ Field3D Div_par_flux(const Field3D& v, const Field3D& f, CELL_LOC outloc, f_B.splitParallelSlices(); f_B.yup() = f.yup() / Bxy_floc; f_B.ydown() = f.ydown() / Bxy_floc; - return metric->Bxy * FDDY(v, f_B, outloc, method) / sqrt(metric->g_22); + return metric->Bxy() * FDDY(v, f_B, outloc, method) / sqrt(metric->g_22()); } Field3D Div_par_flux(const Field3D& v, const Field3D& f, const std::string& method, @@ -469,16 +469,16 @@ Coordinates::FieldMetric b0xGrad_dot_Grad(const Field2D& phi, const Field2D& A, Coordinates* metric = phi.getCoordinates(outloc); // Calculate phi derivatives - Coordinates::FieldMetric dpdx = DDX(phi, outloc); - Coordinates::FieldMetric dpdy = DDY(phi, outloc); + Coordinates::FieldMetric const dpdx = DDX(phi, outloc); + Coordinates::FieldMetric const dpdy = DDY(phi, outloc); // Calculate advection velocity - Coordinates::FieldMetric vx = -metric->g_23 * dpdy; - Coordinates::FieldMetric vy = metric->g_23 * dpdx; + Coordinates::FieldMetric const vx = -metric->g_23() * dpdy; + Coordinates::FieldMetric const vy = metric->g_23() * dpdx; // Upwind A using these velocities Coordinates::FieldMetric result = VDDX(vx, A, outloc) + VDDY(vy, A, outloc); - result /= metric->J * sqrt(metric->g_22); + result /= metric->J() * sqrt(metric->g_22()); ASSERT1(result.getLocation() == outloc); @@ -502,24 +502,24 @@ Field3D b0xGrad_dot_Grad(const Field2D& phi, const Field3D& A, CELL_LOC outloc) Coordinates* metric = phi.getCoordinates(outloc); // Calculate phi derivatives - Coordinates::FieldMetric dpdx = DDX(phi, outloc); - Coordinates::FieldMetric dpdy = DDY(phi, outloc); + Coordinates::FieldMetric const dpdx = DDX(phi, outloc); + Coordinates::FieldMetric const dpdy = DDY(phi, outloc); // Calculate advection velocity - Coordinates::FieldMetric vx = -metric->g_23 * dpdy; - Coordinates::FieldMetric vy = metric->g_23 * dpdx; - Coordinates::FieldMetric vz = metric->g_12 * dpdy - metric->g_22 * dpdx; + Coordinates::FieldMetric const vx = -metric->g_23() * dpdy; + Coordinates::FieldMetric const vy = metric->g_23() * dpdx; + Coordinates::FieldMetric vz = metric->g_12() * dpdy - metric->g_22() * dpdx; if (mesh->IncIntShear) { // BOUT-06 style differencing - vz += metric->IntShiftTorsion * vx; + vz += metric->IntShiftTorsion() * vx; } // Upwind A using these velocities Field3D result = VDDX(vx, A, outloc) + VDDY(vy, A, outloc) + VDDZ(vz, A, outloc); - result /= (metric->J * sqrt(metric->g_22)); + result /= (metric->J() * sqrt(metric->g_22())); #if BOUT_USE_TRACK result.name = "b0xGrad_dot_Grad(" + phi.name + "," + A.name + ")"; @@ -542,19 +542,19 @@ Field3D b0xGrad_dot_Grad(const Field3D& p, const Field2D& A, CELL_LOC outloc) { Coordinates* metric = p.getCoordinates(outloc); // Calculate phi derivatives - Field3D dpdx = DDX(p, outloc); - Field3D dpdy = DDY(p, outloc); - Field3D dpdz = DDZ(p, outloc); + Field3D const dpdx = DDX(p, outloc); + Field3D const dpdy = DDY(p, outloc); + Field3D const dpdz = DDZ(p, outloc); // Calculate advection velocity - Field3D vx = metric->g_22 * dpdz - metric->g_23 * dpdy; - Field3D vy = metric->g_23 * dpdx - metric->g_12 * dpdz; + Field3D const vx = metric->g_22() * dpdz - metric->g_23() * dpdy; + Field3D const vy = metric->g_23() * dpdx - metric->g_12() * dpdz; // Upwind A using these velocities Field3D result = VDDX(vx, A, outloc) + VDDY(vy, A, outloc); - result /= (metric->J * sqrt(metric->g_22)); + result /= (metric->J() * sqrt(metric->g_22())); #if BOUT_USE_TRACK result.name = "b0xGrad_dot_Grad(" + p.name + "," + A.name + ")"; @@ -579,23 +579,23 @@ Field3D b0xGrad_dot_Grad(const Field3D& phi, const Field3D& A, CELL_LOC outloc) Coordinates* metric = phi.getCoordinates(outloc); // Calculate phi derivatives - Field3D dpdx = DDX(phi, outloc); - Field3D dpdy = DDY(phi, outloc); - Field3D dpdz = DDZ(phi, outloc); + Field3D const dpdx = DDX(phi, outloc); + Field3D const dpdy = DDY(phi, outloc); + Field3D const dpdz = DDZ(phi, outloc); // Calculate advection velocity - Field3D vx = metric->g_22 * dpdz - metric->g_23 * dpdy; - Field3D vy = metric->g_23 * dpdx - metric->g_12 * dpdz; - Field3D vz = metric->g_12 * dpdy - metric->g_22 * dpdx; + Field3D const vx = metric->g_22() * dpdz - metric->g_23() * dpdy; + Field3D const vy = metric->g_23() * dpdx - metric->g_12() * dpdz; + Field3D vz = metric->g_12() * dpdy - metric->g_22() * dpdx; if (mesh->IncIntShear) { // BOUT-06 style differencing - vz += metric->IntShiftTorsion * vx; + vz += metric->IntShiftTorsion() * vx; } Field3D result = VDDX(vx, A, outloc) + VDDY(vy, A, outloc) + VDDZ(vz, A, outloc); - result /= (metric->J * sqrt(metric->g_22)); + result /= (metric->J() * sqrt(metric->g_22())); #if BOUT_USE_TRACK result.name = "b0xGrad_dot_Grad(" + phi.name + "," + A.name + ")"; @@ -630,7 +630,7 @@ Coordinates::FieldMetric bracket(const Field2D& f, const Field2D& g, result.setLocation(outloc); } else { // Use full expression with all terms - result = b0xGrad_dot_Grad(f, g, outloc) / f.getCoordinates(outloc)->Bxy; + result = b0xGrad_dot_Grad(f, g, outloc) / f.getCoordinates(outloc)->Bxy(); } return result; } @@ -666,13 +666,13 @@ Field3D bracket(const Field3D& f, const Field2D& g, BRACKET_METHOD method, for (int x = mesh->xstart; x <= mesh->xend; x++) { for (int y = mesh->ystart; y <= mesh->yend; y++) { for (int z = 0; z < ncz; z++) { - int zm = (z - 1 + ncz) % ncz; - int zp = (z + 1) % ncz; + int const zm = (z - 1 + ncz) % ncz; + int const zp = (z + 1) % ncz; BoutReal gp, gm; // Vx = DDZ(f) - BoutReal vx = (f(x, y, zp) - f(x, y, zm)) / (2. * metric->dz(x, y, z)); + BoutReal const vx = (f(x, y, zp) - f(x, y, zm)) / (2. * metric->dz(x, y, z)); // Set stability condition solver->setMaxTimestep(metric->dx(x, y, z) / (fabs(vx) + 1e-16)); @@ -706,7 +706,7 @@ Field3D bracket(const Field3D& f, const Field2D& g, BRACKET_METHOD method, BOUT_FOR(j2D, result.getRegion2D("RGN_NOBNDRY")) { // Get constants for this iteration - const BoutReal spacingFactor = 1.0 / (12 * metric->dz[j2D] * metric->dx[j2D]); + const BoutReal spacingFactor = 1.0 / (12 * metric->dz()[j2D] * metric->dx()[j2D]); const int jy = j2D.y(), jx = j2D.x(); const int xm = jx - 1, xp = jx + 1; @@ -786,21 +786,22 @@ Field3D bracket(const Field3D& f, const Field2D& g, BRACKET_METHOD method, // Above is alternative to const int jzmTmp = (jz - 1 + ncz) % ncz; // J++ = DDZ(f)*DDX(g) - DDX(f)*DDZ(g) - BoutReal Jpp = + BoutReal const Jpp = ((f(jx, jy, jzp) - f(jx, jy, jzm)) * (g(jx + 1, jy) - g(jx - 1, jy)) - (f(jx + 1, jy, jz) - f(jx - 1, jy, jz)) * (g(jx, jy) - g(jx, jy))); // J+x - BoutReal Jpx = (g(jx + 1, jy) * (f(jx + 1, jy, jzp) - f(jx + 1, jy, jzm)) - - g(jx - 1, jy) * (f(jx - 1, jy, jzp) - f(jx - 1, jy, jzm)) - - g(jx, jy) * (f(jx + 1, jy, jzp) - f(jx - 1, jy, jzp)) - + g(jx, jy) * (f(jx + 1, jy, jzm) - f(jx - 1, jy, jzm))); + BoutReal const Jpx = + (g(jx + 1, jy) * (f(jx + 1, jy, jzp) - f(jx + 1, jy, jzm)) + - g(jx - 1, jy) * (f(jx - 1, jy, jzp) - f(jx - 1, jy, jzm)) + - g(jx, jy) * (f(jx + 1, jy, jzp) - f(jx - 1, jy, jzp)) + + g(jx, jy) * (f(jx + 1, jy, jzm) - f(jx - 1, jy, jzm))); // Jx+ - BoutReal Jxp = (g(jx + 1, jy) * (f(jx, jy, jzp) - f(jx + 1, jy, jz)) - - g(jx - 1, jy) * (f(jx - 1, jy, jz) - f(jx, jy, jzm)) - - g(jx - 1, jy) * (f(jx, jy, jzp) - f(jx - 1, jy, jz)) - + g(jx + 1, jy) * (f(jx + 1, jy, jz) - f(jx, jy, jzm))); + BoutReal const Jxp = (g(jx + 1, jy) * (f(jx, jy, jzp) - f(jx + 1, jy, jz)) + - g(jx - 1, jy) * (f(jx - 1, jy, jz) - f(jx, jy, jzm)) + - g(jx - 1, jy) * (f(jx, jy, jzp) - f(jx - 1, jy, jz)) + + g(jx + 1, jy) * (f(jx + 1, jy, jz) - f(jx, jy, jzm))); result(jx, jy, jz) = (Jpp + Jpx + Jxp) * spacingFactor; } @@ -818,7 +819,7 @@ Field3D bracket(const Field3D& f, const Field2D& g, BRACKET_METHOD method, } default: { // Use full expression with all terms - result = b0xGrad_dot_Grad(f, g, outloc) / metric->Bxy; + result = b0xGrad_dot_Grad(f, g, outloc) / metric->Bxy(); } } return result; @@ -832,7 +833,7 @@ Field3D bracket(const Field2D& f, const Field3D& g, BRACKET_METHOD method, if (outloc == CELL_DEFAULT) { outloc = g.getLocation(); } - ASSERT1(outloc == g.getLocation()) + ASSERT1(outloc == g.getLocation()); Mesh* mesh = f.getMesh(); @@ -854,7 +855,7 @@ Field3D bracket(const Field2D& f, const Field3D& g, BRACKET_METHOD method, default: { // Use full expression with all terms Coordinates* metric = f.getCoordinates(outloc); - result = b0xGrad_dot_Grad(f, g, outloc) / metric->Bxy; + result = b0xGrad_dot_Grad(f, g, outloc) / metric->Bxy(); } } @@ -893,7 +894,7 @@ Field3D bracket(const Field3D& f, const Field3D& g, BRACKET_METHOD method, } // Get current timestep - BoutReal dt = solver->getCurrentTimestep(); + BoutReal const dt = solver->getCurrentTimestep(); FieldPerp vx(mesh), vz(mesh); vx.allocate(); @@ -901,12 +902,12 @@ Field3D bracket(const Field3D& f, const Field3D& g, BRACKET_METHOD method, vz.allocate(); vz.setLocation(outloc); - int ncz = mesh->LocalNz; + int const ncz = mesh->LocalNz; for (int y = mesh->ystart; y <= mesh->yend; y++) { for (int x = 1; x <= mesh->LocalNx - 2; x++) { for (int z = 0; z < mesh->LocalNz; z++) { - int zm = (z - 1 + ncz) % ncz; - int zp = (z + 1) % ncz; + int const zm = (z - 1 + ncz) % ncz; + int const zp = (z + 1) % ncz; // Vx = DDZ(f) vx(x, z) = (f(x, y, zp) - f(x, y, zm)) / (2. * metric->dz(x, y, z)); @@ -925,8 +926,8 @@ Field3D bracket(const Field3D& f, const Field3D& g, BRACKET_METHOD method, for (int x = mesh->xstart; x <= mesh->xend; x++) { for (int z = 0; z < ncz; z++) { - int zm = (z - 1 + ncz) % ncz; - int zp = (z + 1) % ncz; + int const zm = (z - 1 + ncz) % ncz; + int const zp = (z + 1) % ncz; BoutReal gp, gm; @@ -999,7 +1000,7 @@ Field3D bracket(const Field3D& f, const Field3D& g, BRACKET_METHOD method, BOUT_FOR(j2D, result.getRegion2D("RGN_NOBNDRY")) { #if not(BOUT_USE_METRIC_3D) - const BoutReal spacingFactor = 1.0 / (12 * metric->dz[j2D] * metric->dx[j2D]); + const BoutReal spacingFactor = 1.0 / (12 * metric->dz()[j2D] * metric->dx()[j2D]); #endif const int jy = j2D.y(), jx = j2D.x(); const int xm = jx - 1, xp = jx + 1; @@ -1154,7 +1155,7 @@ Field3D bracket(const Field3D& f, const Field3D& g, BRACKET_METHOD method, } default: { // Use full expression with all terms - result = b0xGrad_dot_Grad(f, g, outloc) / metric->Bxy; + result = b0xGrad_dot_Grad(f, g, outloc) / metric->Bxy(); } } diff --git a/src/mesh/fv_ops.cxx b/src/mesh/fv_ops.cxx index cd5b924e9e..96a95f4cd9 100644 --- a/src/mesh/fv_ops.cxx +++ b/src/mesh/fv_ops.cxx @@ -34,8 +34,8 @@ Field3D Div_a_Grad_perp(const Field3D& a, const Field3D& f) { // Flux in x - int xs = mesh->xstart - 1; - int xe = mesh->xend; + int const xs = mesh->xstart - 1; + int const xe = mesh->xend; /* if(mesh->firstX()) @@ -51,11 +51,11 @@ Field3D Div_a_Grad_perp(const Field3D& a, const Field3D& f) { for (int k = 0; k < mesh->LocalNz; k++) { // Calculate flux from i to i+1 - BoutReal fout = 0.5 * (a(i, j, k) + a(i + 1, j, k)) - * (coord->J(i, j, k) * coord->g11(i, j, k) - + coord->J(i + 1, j, k) * coord->g11(i + 1, j, k)) - * (f(i + 1, j, k) - f(i, j, k)) - / (coord->dx(i, j, k) + coord->dx(i + 1, j, k)); + BoutReal const fout = 0.5 * (a(i, j, k) + a(i + 1, j, k)) + * (coord->J(i, j, k) * coord->g11(i, j, k) + + coord->J(i + 1, j, k) * coord->g11(i + 1, j, k)) + * (f(i + 1, j, k) - f(i, j, k)) + / (coord->dx(i, j, k) + coord->dx(i + 1, j, k)); result(i, j, k) += fout / (coord->dx(i, j, k) * coord->J(i, j, k)); result(i + 1, j, k) -= fout / (coord->dx(i + 1, j, k) * coord->J(i + 1, j, k)); @@ -69,9 +69,9 @@ Field3D Div_a_Grad_perp(const Field3D& a, const Field3D& f) { // 3D Metric, need yup/ydown fields. // Requires previous communication of metrics // -- should insert communication here? - if (!coord->g23.hasParallelSlices() || !coord->g_23.hasParallelSlices() - || !coord->dy.hasParallelSlices() || !coord->dz.hasParallelSlices() - || !coord->Bxy.hasParallelSlices() || !coord->J.hasParallelSlices()) { + if (!coord->g23().hasParallelSlices() || !coord->g_23().hasParallelSlices() + || !coord->dy().hasParallelSlices() || !coord->dz().hasParallelSlices() + || !coord->Bxy().hasParallelSlices() || !coord->J().hasParallelSlices()) { throw BoutException("metrics have no yup/down: Maybe communicate in init?"); } } @@ -87,12 +87,12 @@ Field3D Div_a_Grad_perp(const Field3D& a, const Field3D& f) { // Only in 3D case with FCI do the metrics have parallel slices const bool metric_fci = fci and bout::build::use_metric_3d; - const auto g23 = makeslices(metric_fci, coord->g23); - const auto g_23 = makeslices(metric_fci, coord->g_23); - const auto J = makeslices(metric_fci, coord->J); - const auto dy = makeslices(metric_fci, coord->dy); - const auto dz = makeslices(metric_fci, coord->dz); - const auto Bxy = makeslices(metric_fci, coord->Bxy); + const auto g23 = makeslices(metric_fci, coord->g23()); + const auto g_23 = makeslices(metric_fci, coord->g_23()); + const auto J = makeslices(metric_fci, coord->J()); + const auto dy = makeslices(metric_fci, coord->dy()); + const auto dz = makeslices(metric_fci, coord->dz()); + const auto Bxy = makeslices(metric_fci, coord->Bxy()); // Result of the Y and Z fluxes Field3D yzresult(0.0, mesh); @@ -156,7 +156,7 @@ Field3D Div_a_Grad_perp(const Field3D& a, const Field3D& f) { const BoutReal fout = 0.25 * (a_slice.c[i] + a_slice.c[ikp]) - * (J.c[i] * coord->g33[i] + J.c[ikp] * coord->g33[ikp]) + * (J.c[i] * coord->g33()[i] + J.c[ikp] * coord->g33()[ikp]) * ( // df/dz (f_slice.c[ikp] - f_slice.c[i]) / dz.c[i] // - g_yz * df/dy / SQ(J*B) @@ -187,7 +187,7 @@ const Field3D Div_par_K_Grad_par(const Field3D& Kin, const Field3D& fin, Mesh* mesh = Kin.getMesh(); - bool use_parallel_slices = (Kin.hasParallelSlices() && fin.hasParallelSlices()); + bool const use_parallel_slices = (Kin.hasParallelSlices() && fin.hasParallelSlices()); const auto& K = use_parallel_slices ? Kin : toFieldAligned(Kin, "RGN_NOX"); const auto& f = use_parallel_slices ? fin : toFieldAligned(fin, "RGN_NOX"); @@ -211,30 +211,32 @@ const Field3D Div_par_K_Grad_par(const Field3D& Kin, const Field3D& fin, if (bndry_flux || mesh->periodicY(i.x()) || !mesh->lastY(i.x()) || (i.y() != mesh->yend)) { - BoutReal c = 0.5 * (K[i] + Kup[iyp]); // K at the upper boundary - BoutReal J = 0.5 * (coord->J[i] + coord->J[iyp]); // Jacobian at boundary - BoutReal g_22 = 0.5 * (coord->g_22[i] + coord->g_22[iyp]); + BoutReal const c = 0.5 * (K[i] + Kup[iyp]); // K at the upper boundary + BoutReal const J = 0.5 * (coord->J()[i] + coord->J()[iyp]); // Jacobian at boundary + BoutReal const g_22 = 0.5 * (coord->g_22()[i] + coord->g_22()[iyp]); - BoutReal gradient = 2. * (fup[iyp] - f[i]) / (coord->dy[i] + coord->dy[iyp]); + BoutReal const gradient = + 2. * (fup[iyp] - f[i]) / (coord->dy()[i] + coord->dy()[iyp]); - BoutReal flux = c * J * gradient / g_22; + BoutReal const flux = c * J * gradient / g_22; - result[i] += flux / (coord->dy[i] * coord->J[i]); + result[i] += flux / (coord->dy()[i] * coord->J()[i]); } // Calculate flux at lower surface if (bndry_flux || mesh->periodicY(i.x()) || !mesh->firstY(i.x()) || (i.y() != mesh->ystart)) { - BoutReal c = 0.5 * (K[i] + Kdown[iym]); // K at the lower boundary - BoutReal J = 0.5 * (coord->J[i] + coord->J[iym]); // Jacobian at boundary + BoutReal const c = 0.5 * (K[i] + Kdown[iym]); // K at the lower boundary + BoutReal const J = 0.5 * (coord->J()[i] + coord->J()[iym]); // Jacobian at boundary - BoutReal g_22 = 0.5 * (coord->g_22[i] + coord->g_22[iym]); + BoutReal const g_22 = 0.5 * (coord->g_22()[i] + coord->g_22()[iym]); - BoutReal gradient = 2. * (f[i] - fdown[iym]) / (coord->dy[i] + coord->dy[iym]); + BoutReal const gradient = + 2. * (f[i] - fdown[iym]) / (coord->dy()[i] + coord->dy()[iym]); - BoutReal flux = c * J * gradient / g_22; + BoutReal const flux = c * J * gradient / g_22; - result[i] -= flux / (coord->dy[i] * coord->J[i]); + result[i] -= flux / (coord->dy()[i] * coord->J()[i]); } } @@ -265,9 +267,9 @@ const Field3D D4DY4(const Field3D& d_in, const Field3D& f_in) { for (int i = mesh->xstart; i <= mesh->xend; i++) { // Check for boundaries - bool yperiodic = mesh->periodicY(i); - bool has_upper_boundary = !yperiodic && mesh->lastY(i); - bool has_lower_boundary = !yperiodic && mesh->firstY(i); + bool const yperiodic = mesh->periodicY(i); + bool const has_upper_boundary = !yperiodic && mesh->lastY(i); + bool const has_lower_boundary = !yperiodic && mesh->firstY(i); // Always calculate fluxes at upper Y cell boundary const int ystart = @@ -283,18 +285,18 @@ const Field3D D4DY4(const Field3D& d_in, const Field3D& f_in) { for (int j = ystart; j <= yend; j++) { for (int k = 0; k < mesh->LocalNz; k++) { - BoutReal dy3 = SQ(coord->dy(i, j, k)) * coord->dy(i, j, k); + BoutReal const dy3 = SQ(coord->dz(i, j, k)) * coord->dz(i, j, k); // 3rd derivative at upper boundary - BoutReal d3fdy3 = + BoutReal const d3fdy3 = (f(i, j + 2, k) - 3. * f(i, j + 1, k) + 3. * f(i, j, k) - f(i, j - 1, k)) / dy3; - BoutReal flux = 0.5 * (d(i, j, k) + d(i, j + 1, k)) - * (coord->J(i, j, k) + coord->J(i, j + 1, k)) * d3fdy3; + BoutReal const flux = 0.5 * (d(i, j, k) + d(i, j + 1, k)) + * (coord->J(i, j, k) + coord->J(i, j + 1, k)) * d3fdy3; - result(i, j, k) += flux / (coord->J(i, j, k) * coord->dy(i, j, k)); - result(i, j + 1, k) -= flux / (coord->J(i, j + 1, k) * coord->dy(i, j + 1, k)); + result(i, j, k) += flux / (coord->J(i, j, k) * coord->dz(i, j, k)); + result(i, j + 1, k) -= flux / (coord->J(i, j + 1, k) * coord->dz(i, j + 1, k)); } } } @@ -315,10 +317,10 @@ const Field3D D4DY4_Index(const Field3D& f_in, bool bndry_flux) { Coordinates* coord = f_in.getCoordinates(); for (int i = mesh->xstart; i <= mesh->xend; i++) { - bool yperiodic = mesh->periodicY(i); + bool const yperiodic = mesh->periodicY(i); - bool has_upper_boundary = !yperiodic && mesh->lastY(i); - bool has_lower_boundary = !yperiodic && mesh->firstY(i); + bool const has_upper_boundary = !yperiodic && mesh->lastY(i); + bool const has_lower_boundary = !yperiodic && mesh->firstY(i); for (int j = mesh->ystart; j <= mesh->yend; j++) { @@ -332,13 +334,13 @@ const Field3D D4DY4_Index(const Field3D& f_in, bool bndry_flux) { for (int k = 0; k < mesh->LocalNz; k++) { // Right boundary common factors const BoutReal common_factor = 0.25 - * (coord->dy(i, j, k) + coord->dy(i, j + 1, k)) + * (coord->dz(i, j, k) + coord->dz(i, j + 1, k)) * (coord->J(i, j, j) + coord->J(i, j + 1, k)); const BoutReal factor_rc = - common_factor / (coord->J(i, j, k) * coord->dy(i, j, k)); + common_factor / (coord->J(i, j, k) * coord->dz(i, j, k)); const BoutReal factor_rp = - common_factor / (coord->J(i, j + 1, k) * coord->dy(i, j + 1, k)); + common_factor / (coord->J(i, j + 1, k) * coord->dz(i, j + 1, k)); // Not on domain boundary // 3rd derivative at right cell boundary @@ -356,13 +358,13 @@ const Field3D D4DY4_Index(const Field3D& f_in, bool bndry_flux) { for (int k = 0; k < mesh->LocalNz; k++) { // Right boundary common factors const BoutReal common_factor = 0.25 - * (coord->dy(i, j, k) + coord->dy(i, j + 1, k)) + * (coord->dz(i, j, k) + coord->dz(i, j + 1, k)) * (coord->J(i, j, j) + coord->J(i, j + 1, k)); const BoutReal factor_rc = - common_factor / (coord->J(i, j, k) * coord->dy(i, j, k)); + common_factor / (coord->J(i, j, k) * coord->dz(i, j, k)); const BoutReal factor_rp = - common_factor / (coord->J(i, j + 1, k) * coord->dy(i, j + 1, k)); + common_factor / (coord->J(i, j + 1, k) * coord->dz(i, j + 1, k)); const BoutReal d3fdx3 = -((16. / 5) * 0.5 * (f(i, j + 1, k) + f(i, j, k)) // Boundary value f_b @@ -385,13 +387,13 @@ const Field3D D4DY4_Index(const Field3D& f_in, bool bndry_flux) { if (j != mesh->ystart || !has_lower_boundary) { for (int k = 0; k < mesh->LocalNz; k++) { const BoutReal common_factor = 0.25 - * (coord->dy(i, j, k) + coord->dy(i, j + 1, k)) + * (coord->dz(i, j, k) + coord->dz(i, j + 1, k)) * (coord->J(i, j, k) + coord->J(i, j - 1, k)); const BoutReal factor_lc = - common_factor / (coord->J(i, j, k) * coord->dy(i, j, k)); + common_factor / (coord->J(i, j, k) * coord->dz(i, j, k)); const BoutReal factor_lm = - common_factor / (coord->J(i, j - 1, k) * coord->dy(i, j - 1, k)); + common_factor / (coord->J(i, j - 1, k) * coord->dz(i, j - 1, k)); // Not on a domain boundary const BoutReal d3fdx3 = @@ -404,13 +406,13 @@ const Field3D D4DY4_Index(const Field3D& f_in, bool bndry_flux) { // On a domain (Y) boundary for (int k = 0; k < mesh->LocalNz; k++) { const BoutReal common_factor = 0.25 - * (coord->dy(i, j, k) + coord->dy(i, j + 1, k)) + * (coord->dz(i, j, k) + coord->dz(i, j + 1, k)) * (coord->J(i, j, k) + coord->J(i, j - 1, k)); const BoutReal factor_lc = - common_factor / (coord->J(i, j, k) * coord->dy(i, j, k)); + common_factor / (coord->J(i, j, k) * coord->dz(i, j, k)); const BoutReal factor_lm = - common_factor / (coord->J(i, j - 1, k) * coord->dy(i, j - 1, k)); + common_factor / (coord->J(i, j - 1, k) * coord->dz(i, j - 1, k)); const BoutReal d3fdx3 = -(-(16. / 5) * 0.5 * (f(i, j - 1, k) + f(i, j, k)) // Boundary value f_b + 6. * f(i, j, k) // f_0 @@ -438,12 +440,12 @@ void communicateFluxes(Field3D& f) { throw BoutException("communicateFluxes: Sorry!"); } - int size = mesh->LocalNy * mesh->LocalNz; + int const size = mesh->LocalNy * mesh->LocalNz; comm_handle xin, xout; // Cache results to silence spurious compiler warning about xin, // xout possibly being uninitialised when used - bool not_first = !mesh->firstX(); - bool not_last = !mesh->lastX(); + bool const not_first = !mesh->firstX(); + bool const not_last = !mesh->lastX(); if (not_first) { xin = mesh->irecvXIn(f(0, 0), size, 0); } @@ -504,12 +506,12 @@ Field3D Div_Perp_Lap(const Field3D& a, const Field3D& f, CELL_LOC outloc) { for (int k = 0; k < mesh->LocalNz; k++) { // wrap k-index around as Z is (currently) periodic. - int kp = (k + 1) % (mesh->LocalNz); - int km = (k - 1 + mesh->LocalNz) % (mesh->LocalNz); + int const kp = (k + 1) % (mesh->LocalNz); + int const km = (k - 1 + mesh->LocalNz) % (mesh->LocalNz); // Calculate gradients on cell faces -- assumes constant grid spacing - BoutReal gR = + BoutReal const gR = (coords->g11(i, j, k) + coords->g11(i + 1, j, k)) * (f(i + 1, j, k) - f(i, j, k)) / (coords->dx(i + 1, j, k) + coords->dx(i, j, k)) @@ -517,7 +519,7 @@ Field3D Div_Perp_Lap(const Field3D& a, const Field3D& f, CELL_LOC outloc) { * (f(i + 1, j, kp) - f(i + 1, j, km) + f(i, j, kp) - f(i, j, km)) / (4. * coords->dz(i, j, k)); - BoutReal gL = + BoutReal const gL = (coords->g11(i - 1, j, k) + coords->g11(i, j, k)) * (f(i, j, k) - f(i - 1, j, k)) / (coords->dx(i - 1, j, k) + coords->dx(i, j, k)) @@ -525,13 +527,13 @@ Field3D Div_Perp_Lap(const Field3D& a, const Field3D& f, CELL_LOC outloc) { * (f(i - 1, j, kp) - f(i - 1, j, km) + f(i, j, kp) - f(i, j, km)) / (4 * coords->dz(i, j, k)); - BoutReal gD = + BoutReal const gD = coords->g13(i, j, k) * (f(i + 1, j, km) - f(i - 1, j, km) + f(i + 1, j, k) - f(i - 1, j, k)) / (4. * coords->dx(i, j, k)) + coords->g33(i, j, k) * (f(i, j, k) - f(i, j, km)) / coords->dz(i, j, k); - BoutReal gU = + BoutReal const gU = coords->g13(i, j, k) * (f(i + 1, j, kp) - f(i - 1, j, kp) + f(i + 1, j, k) - f(i - 1, j, k)) / (4. * coords->dx(i, j, k)) diff --git a/src/mesh/g_values.cxx b/src/mesh/g_values.cxx new file mode 100644 index 0000000000..c019ab1c41 --- /dev/null +++ b/src/mesh/g_values.cxx @@ -0,0 +1,29 @@ +#include "bout/g_values.hxx" +#include "bout/coordinates.hxx" +#include "bout/derivs.hxx" +#include "bout/mesh.hxx" + +GValues::GValues(const Coordinates& coordinates) { + + const auto& contravariantMetricTensor = coordinates.getContravariantMetricTensor(); + const auto& J = coordinates.J(); + + const auto& g11 = contravariantMetricTensor.g11(); + const auto& g22 = contravariantMetricTensor.g22(); + const auto& g33 = contravariantMetricTensor.g33(); + const auto& g12 = contravariantMetricTensor.g12(); + const auto& g13 = contravariantMetricTensor.g13(); + const auto& g23 = contravariantMetricTensor.g23(); + + auto tmp = J * g12; + Coordinates::communicate(tmp); + G1_m = (DDX(J * g11) + DDY(tmp) + DDZ(J * g13)) / J; + tmp = J * g22; + Coordinates::communicate(tmp); + G2_m = (DDX(J * g12) + DDY(tmp) + DDZ(J * g23)) / J; + tmp = J * g23; + Coordinates::communicate(tmp); + G3_m = (DDX(J * g13) + DDY(tmp) + DDZ(J * g33)) / J; + + G1_m.getMesh()->communicate(G1_m, G2_m, G3_m); +} diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index 8ef651b0cd..faa02a4c33 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -40,9 +40,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -50,7 +47,6 @@ #include #include -#include #include /// MPI type of BoutReal for communications diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index ebecb96700..49d99bd9c9 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -424,7 +424,7 @@ class FFTDerivativeType { template void standard(const T& var, T& result, const std::string& region) const { AUTO_TRACE(); - ASSERT2(meta.derivType == DERIV::Standard) + ASSERT2(meta.derivType == DERIV::Standard); ASSERT2(var.getMesh()->getNguard(direction) >= nGuards); ASSERT2(direction == DIRECTION::Z); // Only in Z for now ASSERT2(stagger == STAGGER::None); // Staggering not currently supported diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 870f3413cd..856ad3661e 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -1,6 +1,5 @@ #include #include -#include #include #include #include @@ -175,6 +174,32 @@ int Mesh::get(Field2D& var, const std::string& name, BoutReal def, bool communic return 0; } +FieldMetric Mesh::get(const std::string& name, BoutReal def, bool communicate, + CELL_LOC location) { + TRACE("Loading field: Mesh::get(FieldMetric, {:s})", name); + + auto var = FieldMetric(this, location); + + const bool failed_to_get_from_GridDataSource = + !source->get(this, var, name, def, location); + if (source == nullptr or failed_to_get_from_GridDataSource) { + // set val to default in source==nullptr too: + var = def; + var.setLocation(location); + return var; + } + + // Communicate to get guard cell data + if (communicate) { + Mesh::communicate(var); + } + + // Check that the data is valid + checkData(var); + + return var; +} + int Mesh::get(Field3D& var, const std::string& name, BoutReal def, bool communicate, CELL_LOC location) { TRACE("Loading 3D field: Mesh::get(Field3D, {:s})", name); @@ -277,10 +302,20 @@ bool Mesh::sourceHasVar(const std::string& name) { } /// Wrapper for GridDataSource::hasXBoundaryGuards -bool Mesh::sourceHasXBoundaryGuards() { return source->hasXBoundaryGuards(this); } +bool Mesh::sourceHasXBoundaryGuards() { + if (!source) { + throw BoutException("Mesh has no source. "); + } + return source->hasXBoundaryGuards(this); +} /// Wrapper for GridDataSource::hasYBoundaryGuards -bool Mesh::sourceHasYBoundaryGuards() { return source->hasYBoundaryGuards(); } +bool Mesh::sourceHasYBoundaryGuards() { + if (!source) { + throw BoutException("Mesh has no source. "); + } + return source->hasYBoundaryGuards(); +} /************************************************************************** * Communications @@ -546,12 +581,11 @@ Mesh::createDefaultCoordinates(const CELL_LOC location, if (location == CELL_CENTRE || location == CELL_DEFAULT) { // Initialize coordinates from input return std::make_shared(this, options); - } else { - // Interpolate coordinates from CELL_CENTRE version - return std::make_shared(this, options, location, - getCoordinates(CELL_CENTRE), - force_interpolate_from_centre); } + // Interpolate coordinates from CELL_CENTRE version + return std::make_shared(this, options, location, + getCoordinates(CELL_CENTRE), + force_interpolate_from_centre); } const Region<>& Mesh::getRegion3D(const std::string& region_name) const { @@ -751,8 +785,14 @@ void Mesh::recalculateStaggeredCoordinates() { continue; } - *coords_map[location] = std::move(*createDefaultCoordinates(location, true)); - coords_map[location]->geometry(false, true); + auto force_interpolate_from_centre = true; + Coordinates& new_coordinates = + *createDefaultCoordinates(location, force_interpolate_from_centre); + *coords_map[location] = std::move(new_coordinates); + + auto recalculate_staggered = false; + new_coordinates.recalculateAndReset(recalculate_staggered, + force_interpolate_from_centre); } } @@ -842,3 +882,8 @@ std::optional Mesh::getCommonRegion(std::optional lhs, } return region3Dintersect[pos]; } + +constexpr decltype(MeshFactory::type_name) MeshFactory::type_name; +constexpr decltype(MeshFactory::section_name) MeshFactory::section_name; +constexpr decltype(MeshFactory::option_name) MeshFactory::option_name; +constexpr decltype(MeshFactory::default_type) MeshFactory::default_type; diff --git a/src/mesh/metric_tensor.cxx b/src/mesh/metric_tensor.cxx new file mode 100644 index 0000000000..81df132d11 --- /dev/null +++ b/src/mesh/metric_tensor.cxx @@ -0,0 +1,130 @@ +#include "bout/metric_tensor.hxx" +#include "fmt/core.h" +#include "bout/bout_types.hxx" +#include "bout/boutexception.hxx" +#include "bout/field2d.hxx" +#include "bout/mesh.hxx" +#include "bout/output.hxx" +#include "bout/region.hxx" +#include "bout/utils.hxx" + +#include +#include + +MetricTensor::MetricTensor(FieldMetric g11, FieldMetric g22, FieldMetric g33, + FieldMetric g12, FieldMetric g13, FieldMetric g23) + : g11_m(std::move(g11)), g22_m(std::move(g22)), g33_m(std::move(g33)), + g12_m(std::move(g12)), g13_m(std::move(g13)), g23_m(std::move(g23)) {} + +MetricTensor::MetricTensor(const BoutReal g11, const BoutReal g22, const BoutReal g33, + const BoutReal g12, const BoutReal g13, const BoutReal g23, + Mesh* mesh) + : g11_m(g11, mesh), g22_m(g22, mesh), g33_m(g33, mesh), g12_m(g12, mesh), + g13_m(g13, mesh), g23_m(g23, mesh) {} + +void MetricTensor::check(int ystart) { + const bool non_identity_parallel_transform = + g11_m.hasParallelSlices() && &g11_m.ynext(1) != &g11_m; + + // Diagonal metric components should be finite + bout::checkFinite(g11_m, "g11", "RGN_NOCORNERS"); + bout::checkFinite(g22_m, "g22", "RGN_NOCORNERS"); + bout::checkFinite(g33_m, "g33", "RGN_NOCORNERS"); + if (non_identity_parallel_transform) { + for (int dy = 1; dy <= ystart; ++dy) { + for (const auto sign : {1, -1}) { + const auto region = fmt::format("RGN_YPAR_{:+d}", sign * dy); + bout::checkFinite(g11_m.ynext(sign * dy), "g11.ynext", region); + bout::checkFinite(g22_m.ynext(sign * dy), "g22.ynext", region); + bout::checkFinite(g33_m.ynext(sign * dy), "g33.ynext", region); + } + } + } + + // Diagonal metric components should be positive + bout::checkPositive(g11_m, "g11", "RGN_NOCORNERS"); + bout::checkPositive(g22_m, "g22", "RGN_NOCORNERS"); + bout::checkPositive(g33_m, "g33", "RGN_NOCORNERS"); + if (non_identity_parallel_transform) { + for (int dy = 1; dy <= ystart; ++dy) { + for (const auto sign : {1, -1}) { + const auto region = fmt::format("RGN_YPAR_{:+d}", sign * dy); + bout::checkPositive(g11_m.ynext(sign * dy), "g11.ynext", region); + bout::checkPositive(g22_m.ynext(sign * dy), "g22.ynext", region); + bout::checkPositive(g33_m.ynext(sign * dy), "g33.ynext", region); + } + } + } + + // Off-diagonal metric components should be finite + bout::checkFinite(g12_m, "g12", "RGN_NOCORNERS"); + bout::checkFinite(g13_m, "g13", "RGN_NOCORNERS"); + bout::checkFinite(g23_m, "g23", "RGN_NOCORNERS"); + if (non_identity_parallel_transform) { + for (int dy = 1; dy <= ystart; ++dy) { + for (const auto sign : {1, -1}) { + const auto region = fmt::format("RGN_YPAR_{:+d}", sign * dy); + bout::checkFinite(g12_m.ynext(sign * dy), "g12.ynext", region); + bout::checkFinite(g13_m.ynext(sign * dy), "g13.ynext", region); + bout::checkFinite(g23_m.ynext(sign * dy), "g23.ynext", region); + } + } + } +} + +MetricTensor MetricTensor::inverse(const std::string& region) { + + TRACE("MetricTensor::inverse"); + + // Perform inversion of g{ij} to get g^{ij}, or vice versa + auto matrix = Matrix(3, 3); + + FieldMetric g_11 = emptyFrom(g11_m); + FieldMetric g_22 = emptyFrom(g22_m); + FieldMetric g_33 = emptyFrom(g33_m); + FieldMetric g_12 = emptyFrom(g12_m); + FieldMetric g_13 = emptyFrom(g13_m); + FieldMetric g_23 = emptyFrom(g23_m); + + BOUT_FOR_SERIAL(i, g11_m.getRegion(region)) { + matrix(0, 0) = g11_m[i]; + matrix(1, 1) = g22_m[i]; + matrix(2, 2) = g33_m[i]; + + matrix(0, 1) = matrix(1, 0) = g12_m[i]; + matrix(1, 2) = matrix(2, 1) = g23_m[i]; + matrix(0, 2) = matrix(2, 0) = g13_m[i]; + + if (invert3x3(matrix) != 0) { + const auto error_message = fmt::format( + "\tERROR: metric tensor is singular at ({:d}, {:d})\n", i.x(), i.y()); + output_error.write(error_message); + throw BoutException(error_message); + } + + g_11[i] = matrix(0, 0); + g_22[i] = matrix(1, 1); + g_33[i] = matrix(2, 2); + g_12[i] = matrix(0, 1); + g_13[i] = matrix(0, 2); + g_23[i] = matrix(1, 2); + } + + const BoutReal diagonal_maxerr = + BOUTMAX(max(abs((g_11 * g_11 + g_12 * g_12 + g_13 * g_13) - 1)), + max(abs((g_12 * g_12 + g_22 * g_22 + g_23 * g_23) - 1)), + max(abs((g_13 * g_13 + g_23 * g_23 + g_33 * g_33) - 1))); + + output_info.write("\tMaximum error in diagonal inversion is {:e}\n", diagonal_maxerr); + + const BoutReal off_diagonal_maxerr = + BOUTMAX(max(abs(g_11 * g_12 + g_12 * g_22 + g_13 * g_23)), + max(abs(g_11 * g_13 + g_12 * g_23 + g_13 * g_33)), + max(abs(g_12 * g_13 + g_22 * g_23 + g_23 * g_33))); + + output_info.write("\tMaximum error in off-diagonal inversion is {:e}\n", + off_diagonal_maxerr); + + g_11.getMesh()->communicate(g_11, g_22, g_33, g_12, g_13, g_23); + return MetricTensor(g_11, g_22, g_33, g_12, g_13, g_23); +} diff --git a/src/physics/smoothing.cxx b/src/physics/smoothing.cxx index 78ac1814a5..10d5b070be 100644 --- a/src/physics/smoothing.cxx +++ b/src/physics/smoothing.cxx @@ -359,7 +359,7 @@ BoutReal Vol_Integral(const Field2D& var) { BoutReal Int_Glb; Coordinates* metric = var.getCoordinates(); - auto result = metric->J * var * metric->dx * metric->dy; + auto result = metric->J() * var * metric->dx() * metric->dy(); Int_Glb = Average_XY(result); Int_Glb *= static_cast( diff --git a/src/sys/derivs.cxx b/src/sys/derivs.cxx index ee9bcbcc2c..b48a7b0f49 100644 --- a/src/sys/derivs.cxx +++ b/src/sys/derivs.cxx @@ -73,7 +73,7 @@ Coordinates::FieldMetric DDX(const Field2D& f, CELL_LOC outloc, const std::strin Field3D DDY(const Field3D& f, CELL_LOC outloc, const std::string& method, const std::string& region) { return bout::derivatives::index::DDY(f, outloc, method, region) - / f.getCoordinates(outloc)->dy; + / f.getCoordinates(outloc)->dy(); } Coordinates::FieldMetric DDY(const Field2D& f, CELL_LOC outloc, const std::string& method, @@ -86,7 +86,7 @@ Coordinates::FieldMetric DDY(const Field2D& f, CELL_LOC outloc, const std::strin Field3D DDZ(const Field3D& f, CELL_LOC outloc, const std::string& method, const std::string& region) { return bout::derivatives::index::DDZ(f, outloc, method, region) - / f.getCoordinates(outloc)->dz; + / f.getCoordinates(outloc)->dz(); } Coordinates::FieldMetric DDZ(const Field2D& f, CELL_LOC UNUSED(outloc), @@ -104,21 +104,21 @@ Vector3D DDZ(const Vector3D& v, CELL_LOC outloc, const std::string& method, if (v.covariant) { // From equation (2.6.32) in D'Haeseleer - result.x = DDZ(v.x, outloc, method, region) - v.x * metric->G1_13 - - v.y * metric->G2_13 - v.z * metric->G3_13; - result.y = DDZ(v.y, outloc, method, region) - v.x * metric->G1_23 - - v.y * metric->G2_23 - v.z * metric->G3_23; - result.z = DDZ(v.z, outloc, method, region) - v.x * metric->G1_33 - - v.y * metric->G2_33 - v.z * metric->G3_33; + result.x = DDZ(v.x, outloc, method, region) - v.x * metric->G1_13() + - v.y * metric->G2_13() - v.z * metric->G3_13(); + result.y = DDZ(v.y, outloc, method, region) - v.x * metric->G1_23() + - v.y * metric->G2_23() - v.z * metric->G3_23(); + result.z = DDZ(v.z, outloc, method, region) - v.x * metric->G1_33() + - v.y * metric->G2_33() - v.z * metric->G3_33(); result.covariant = true; } else { // From equation (2.6.31) in D'Haeseleer - result.x = DDZ(v.x, outloc, method, region) + v.x * metric->G1_13 - + v.y * metric->G1_23 + v.z * metric->G1_33; - result.y = DDZ(v.y, outloc, method, region) + v.x * metric->G2_13 - + v.y * metric->G2_23 + v.z * metric->G2_33; - result.z = DDZ(v.z, outloc, method, region) + v.x * metric->G3_13 - + v.y * metric->G3_23 + v.z * metric->G3_33; + result.x = DDZ(v.x, outloc, method, region) + v.x * metric->G1_13() + + v.y * metric->G1_23() + v.z * metric->G1_33(); + result.y = DDZ(v.y, outloc, method, region) + v.x * metric->G2_13() + + v.y * metric->G2_23() + v.z * metric->G2_33(); + result.z = DDZ(v.z, outloc, method, region) + v.x * metric->G3_13() + + v.y * metric->G3_23() + v.z * metric->G3_33(); result.covariant = false; } @@ -155,12 +155,13 @@ Field3D D2DX2(const Field3D& f, CELL_LOC outloc, const std::string& method, Coordinates* coords = f.getCoordinates(outloc); Field3D result = - bout::derivatives::index::D2DX2(f, outloc, method, region) / SQ(coords->dx); + bout::derivatives::index::D2DX2(f, outloc, method, region) / SQ(coords->dx()); - if (coords->non_uniform) { + if (coords->non_uniform()) { // Correction for non-uniform f.getMesh() - result += coords->d1_dx * bout::derivatives::index::DDX(f, outloc, "DEFAULT", region) - / coords->dx; + result += coords->d1_dx() + * bout::derivatives::index::DDX(f, outloc, "DEFAULT", region) + / coords->dx(); } ASSERT2(((outloc == CELL_DEFAULT) && (result.getLocation() == f.getLocation())) @@ -174,12 +175,13 @@ Coordinates::FieldMetric D2DX2(const Field2D& f, CELL_LOC outloc, Coordinates* coords = f.getCoordinates(outloc); auto result = - bout::derivatives::index::D2DX2(f, outloc, method, region) / SQ(coords->dx); + bout::derivatives::index::D2DX2(f, outloc, method, region) / SQ(coords->dx()); - if (coords->non_uniform) { + if (coords->non_uniform()) { // Correction for non-uniform f.getMesh() - result += coords->d1_dx * bout::derivatives::index::DDX(f, outloc, "DEFAULT", region) - / coords->dx; + result += coords->d1_dx() + * bout::derivatives::index::DDX(f, outloc, "DEFAULT", region) + / coords->dx(); } return result; @@ -192,12 +194,13 @@ Field3D D2DY2(const Field3D& f, CELL_LOC outloc, const std::string& method, Coordinates* coords = f.getCoordinates(outloc); Field3D result = - bout::derivatives::index::D2DY2(f, outloc, method, region) / SQ(coords->dy); + bout::derivatives::index::D2DY2(f, outloc, method, region) / SQ(coords->dy()); - if (coords->non_uniform) { + if (coords->non_uniform()) { // Correction for non-uniform f.getMesh() - result += coords->d1_dy * bout::derivatives::index::DDY(f, outloc, "DEFAULT", region) - / coords->dy; + result += coords->d1_dy() + * bout::derivatives::index::DDY(f, outloc, "DEFAULT", region) + / coords->dy(); } ASSERT2(((outloc == CELL_DEFAULT) && (result.getLocation() == f.getLocation())) @@ -211,11 +214,12 @@ Coordinates::FieldMetric D2DY2(const Field2D& f, CELL_LOC outloc, Coordinates* coords = f.getCoordinates(outloc); auto result = - bout::derivatives::index::D2DY2(f, outloc, method, region) / SQ(coords->dy); - if (coords->non_uniform) { + bout::derivatives::index::D2DY2(f, outloc, method, region) / SQ(coords->dy()); + if (coords->non_uniform()) { // Correction for non-uniform f.getMesh() - result += coords->d1_dy * bout::derivatives::index::DDY(f, outloc, "DEFAULT", region) - / coords->dy; + result += coords->d1_dy() + * bout::derivatives::index::DDY(f, outloc, "DEFAULT", region) + / coords->dy(); } return result; @@ -226,13 +230,13 @@ Coordinates::FieldMetric D2DY2(const Field2D& f, CELL_LOC outloc, Field3D D2DZ2(const Field3D& f, CELL_LOC outloc, const std::string& method, const std::string& region) { return bout::derivatives::index::D2DZ2(f, outloc, method, region) - / SQ(f.getCoordinates(outloc)->dz); + / SQ(f.getCoordinates(outloc)->dz()); } Coordinates::FieldMetric D2DZ2(const Field2D& f, CELL_LOC outloc, const std::string& method, const std::string& region) { return bout::derivatives::index::D2DZ2(f, outloc, method, region) - / SQ(f.getCoordinates(outloc)->dz); + / SQ(f.getCoordinates(outloc)->dz()); } /******************************************************************************* @@ -242,37 +246,37 @@ Coordinates::FieldMetric D2DZ2(const Field2D& f, CELL_LOC outloc, Field3D D4DX4(const Field3D& f, CELL_LOC outloc, const std::string& method, const std::string& region) { return bout::derivatives::index::D4DX4(f, outloc, method, region) - / SQ(SQ(f.getCoordinates(outloc)->dx)); + / SQ(SQ(f.getCoordinates(outloc)->dx())); } Coordinates::FieldMetric D4DX4(const Field2D& f, CELL_LOC outloc, const std::string& method, const std::string& region) { return bout::derivatives::index::D4DX4(f, outloc, method, region) - / SQ(SQ(f.getCoordinates(outloc)->dx)); + / SQ(SQ(f.getCoordinates(outloc)->dx())); } Field3D D4DY4(const Field3D& f, CELL_LOC outloc, const std::string& method, const std::string& region) { return bout::derivatives::index::D4DY4(f, outloc, method, region) - / SQ(SQ(f.getCoordinates(outloc)->dy)); + / SQ(SQ(f.getCoordinates(outloc)->dy())); } Coordinates::FieldMetric D4DY4(const Field2D& f, CELL_LOC outloc, const std::string& method, const std::string& region) { return bout::derivatives::index::D4DY4(f, outloc, method, region) - / SQ(SQ(f.getCoordinates(outloc)->dy)); + / SQ(SQ(f.getCoordinates(outloc)->dy())); } Field3D D4DZ4(const Field3D& f, CELL_LOC outloc, const std::string& method, const std::string& region) { return bout::derivatives::index::D4DZ4(f, outloc, method, region) - / SQ(SQ(f.getCoordinates(outloc)->dz)); + / SQ(SQ(f.getCoordinates(outloc)->dz())); } Coordinates::FieldMetric D4DZ4(const Field2D& f, CELL_LOC outloc, const std::string& method, const std::string& region) { return bout::derivatives::index::D4DZ4(f, outloc, method, region) - / SQ(SQ(f.getCoordinates(outloc)->dz)); + / SQ(SQ(f.getCoordinates(outloc)->dz())); } /******************************************************************************* @@ -390,14 +394,14 @@ Field3D D2DYDZ(const Field3D& f, CELL_LOC outloc, Coordinates::FieldMetric VDDX(const Field2D& v, const Field2D& f, CELL_LOC outloc, const std::string& method, const std::string& region) { return bout::derivatives::index::VDDX(v, f, outloc, method, region) - / f.getCoordinates(outloc)->dx; + / f.getCoordinates(outloc)->dx(); } /// General version for 2 or 3-D objects Field3D VDDX(const Field3D& v, const Field3D& f, CELL_LOC outloc, const std::string& method, const std::string& region) { return bout::derivatives::index::VDDX(v, f, outloc, method, region) - / f.getCoordinates(outloc)->dx; + / f.getCoordinates(outloc)->dx(); } ////////////// Y DERIVATIVE ///////////////// @@ -406,14 +410,14 @@ Field3D VDDX(const Field3D& v, const Field3D& f, CELL_LOC outloc, Coordinates::FieldMetric VDDY(const Field2D& v, const Field2D& f, CELL_LOC outloc, const std::string& method, const std::string& region) { return bout::derivatives::index::VDDY(v, f, outloc, method, region) - / f.getCoordinates(outloc)->dy; + / f.getCoordinates(outloc)->dy(); } // general case Field3D VDDY(const Field3D& v, const Field3D& f, CELL_LOC outloc, const std::string& method, const std::string& region) { return bout::derivatives::index::VDDY(v, f, outloc, method, region) - / f.getCoordinates(outloc)->dy; + / f.getCoordinates(outloc)->dy(); } ////////////// Z DERIVATIVE ///////////////// @@ -422,7 +426,7 @@ Field3D VDDY(const Field3D& v, const Field3D& f, CELL_LOC outloc, Coordinates::FieldMetric VDDZ(const Field2D& v, const Field2D& f, CELL_LOC outloc, const std::string& method, const std::string& region) { return bout::derivatives::index::VDDZ(v, f, outloc, method, region) - / f.getCoordinates(outloc)->dz; + / f.getCoordinates(outloc)->dz(); } // Note that this is zero because no compression is included @@ -432,7 +436,7 @@ Coordinates::FieldMetric VDDZ([[maybe_unused]] const Field3D& v, const Field2D& #if BOUT_USE_METRIC_3D Field3D tmp{f}; return bout::derivatives::index::VDDZ(v, tmp, outloc, method, region) - / f.getCoordinates(outloc)->dz; + / f.getCoordinates(outloc)->dz(); #else if (outloc == CELL_DEFAULT) { outloc = f.getLocation(); @@ -445,7 +449,7 @@ Coordinates::FieldMetric VDDZ([[maybe_unused]] const Field3D& v, const Field2D& Field3D VDDZ(const Field3D& v, const Field3D& f, CELL_LOC outloc, const std::string& method, const std::string& region) { return bout::derivatives::index::VDDZ(v, f, outloc, method, region) - / f.getCoordinates(outloc)->dz; + / f.getCoordinates(outloc)->dz(); } /******************************************************************************* @@ -454,13 +458,13 @@ Field3D VDDZ(const Field3D& v, const Field3D& f, CELL_LOC outloc, Coordinates::FieldMetric FDDX(const Field2D& v, const Field2D& f, CELL_LOC outloc, const std::string& method, const std::string& region) { return bout::derivatives::index::FDDX(v, f, outloc, method, region) - / f.getCoordinates(outloc)->dx; + / f.getCoordinates(outloc)->dx(); } Field3D FDDX(const Field3D& v, const Field3D& f, CELL_LOC outloc, const std::string& method, const std::string& region) { return bout::derivatives::index::FDDX(v, f, outloc, method, region) - / f.getCoordinates(outloc)->dx; + / f.getCoordinates(outloc)->dx(); } ///////////////////////////////////////////////////////////////////////// @@ -468,13 +472,13 @@ Field3D FDDX(const Field3D& v, const Field3D& f, CELL_LOC outloc, Coordinates::FieldMetric FDDY(const Field2D& v, const Field2D& f, CELL_LOC outloc, const std::string& method, const std::string& region) { return bout::derivatives::index::FDDY(v, f, outloc, method, region) - / f.getCoordinates(outloc)->dy; + / f.getCoordinates(outloc)->dy(); } Field3D FDDY(const Field3D& v, const Field3D& f, CELL_LOC outloc, const std::string& method, const std::string& region) { return bout::derivatives::index::FDDY(v, f, outloc, method, region) - / f.getCoordinates(outloc)->dy; + / f.getCoordinates(outloc)->dy(); } ///////////////////////////////////////////////////////////////////////// @@ -482,11 +486,11 @@ Field3D FDDY(const Field3D& v, const Field3D& f, CELL_LOC outloc, Coordinates::FieldMetric FDDZ(const Field2D& v, const Field2D& f, CELL_LOC outloc, const std::string& method, const std::string& region) { return bout::derivatives::index::FDDZ(v, f, outloc, method, region) - / f.getCoordinates(outloc)->dz; + / f.getCoordinates(outloc)->dz(); } Field3D FDDZ(const Field3D& v, const Field3D& f, CELL_LOC outloc, const std::string& method, const std::string& region) { return bout::derivatives::index::FDDZ(v, f, outloc, method, region) - / f.getCoordinates(outloc)->dz; + / f.getCoordinates(outloc)->dz(); } diff --git a/tests/MMS/GBS/gbs.cxx b/tests/MMS/GBS/gbs.cxx index d0d1fcb039..9fed76c119 100644 --- a/tests/MMS/GBS/gbs.cxx +++ b/tests/MMS/GBS/gbs.cxx @@ -279,7 +279,7 @@ int GBS::init(bool restarting) { break; } case 3: { // logB, taken from mesh - logB = log(coords->Bxy); + logB = log(coords->Bxy()); break; } default: @@ -290,14 +290,14 @@ int GBS::init(bool restarting) { phiSolver = Laplacian::create(opt->getSection("phiSolver")); aparSolver = Laplacian::create(opt->getSection("aparSolver")); - dx4 = SQ(SQ(coords->dx)); - dy4 = SQ(SQ(coords->dy)); - dz4 = SQ(SQ(coords->dz)); + dx4 = SQ(SQ(coords->dx())); + dy4 = SQ(SQ(coords->dy())); + dz4 = SQ(SQ(coords->dz())); SAVE_REPEAT(Ve); - output.write("dx = {:e}, dy = {:e}, dz = {:e}\n", coords->dx(2, 2), coords->dy(2, 2), - coords->dz); + output.write("dx = {:e}, dy = {:e}, dz = {:e}\n", (coords->dx())(2, 2), + (coords->dy())(2, 2), coords->dz()); output.write("g11 = {:e}, g22 = {:e}, g33 = {:e}\n", coords->g11(2, 2), coords->g22(2, 2), coords->g33(2, 2)); output.write("g12 = {:e}, g23 = {:e}\n", coords->g12(2, 2), coords->g23(2, 2)); @@ -321,7 +321,7 @@ void GBS::LoadMetric(BoutReal Lnorm, BoutReal Bnorm) { Field2D dx; if (!mesh->get(dx, "dpsi")) { output << "\tUsing dpsi as the x grid spacing\n"; - coords->dx = dx; // Only use dpsi if found + coords->setDx(dx); // Only use dpsi if found } else { // dx will have been read already from the grid output << "\tUsing dx as the x grid spacing\n"; @@ -330,11 +330,11 @@ void GBS::LoadMetric(BoutReal Lnorm, BoutReal Bnorm) { Rxy /= Lnorm; hthe /= Lnorm; sinty *= SQ(Lnorm) * Bnorm; - coords->dx /= SQ(Lnorm) * Bnorm; + coords->setDx(coords->dx() / (SQ(Lnorm) * Bnorm)); Bpxy /= Bnorm; Btxy /= Bnorm; - coords->Bxy /= Bnorm; + coords->setBxy(coords->Bxy() / Bnorm); // Calculate metric components bool ShiftXderivs; @@ -348,23 +348,24 @@ void GBS::LoadMetric(BoutReal Lnorm, BoutReal Bnorm) { sbp = -1.0; } - coords->g11 = SQ(Rxy * Bpxy); - coords->g22 = 1.0 / SQ(hthe); - coords->g33 = SQ(sinty) * coords->g11 + SQ(coords->Bxy) / coords->g11; - coords->g12 = 0.0; - coords->g13 = -sinty * coords->g11; - coords->g23 = -sbp * Btxy / (hthe * Bpxy * Rxy); + const auto g11 = SQ(Rxy * Bpxy); + const auto g22 = 1.0 / SQ(hthe); + const auto g33 = SQ(sinty) * g11 + SQ(coords->Bxy()) / g11; + const auto g12 = 0.0; + const auto g13 = -sinty * g11; + const auto g23 = -sbp * Btxy / (hthe * Bpxy * Rxy); - coords->J = hthe / Bpxy; + const auto g_11 = 1.0 / g11 + SQ(sinty * Rxy); + const auto g_22 = SQ(coords->Bxy() * hthe / Bpxy); + const auto g_33 = Rxy * Rxy; + const auto g_12 = sbp * Btxy * hthe * sinty * Rxy / Bpxy; + const auto g_13 = sinty * Rxy * Rxy; + const auto g_23 = sbp * Btxy * hthe * Rxy / Bpxy; - coords->g_11 = 1.0 / coords->g11 + SQ(sinty * Rxy); - coords->g_22 = SQ(coords->Bxy * hthe / Bpxy); - coords->g_33 = Rxy * Rxy; - coords->g_12 = sbp * Btxy * hthe * sinty * Rxy / Bpxy; - coords->g_13 = sinty * Rxy * Rxy; - coords->g_23 = sbp * Btxy * hthe * Rxy / Bpxy; + coords->setMetricTensor(ContravariantMetricTensor(g11, g22, g33, g12, g13, g23), + CovariantMetricTensor(g_11, g_22, g_33, g_12, g_13, g_23)); - coords->geometry(); + coords->setJ(hthe / Bpxy); } // just define a macro for V_E dot Grad @@ -416,7 +417,7 @@ int GBS::rhs(BoutReal t) { Gi = 0.0; if (ionvis) { Field3D tau_i = Omega_ci * tau_i0 * pow(Ti, 1.5) / Ne; - Gi = -(0.96 * Ti * Ne * tau_i) * (2. * Grad_par(Vi) + C(phi) / coords->Bxy); + Gi = -(0.96 * Ti * Ne * tau_i) * (2. * Grad_par(Vi) + C(phi) / coords->Bxy()); mesh->communicate(Gi); Gi.applyBoundary("neumann"); } else { @@ -429,7 +430,8 @@ int GBS::rhs(BoutReal t) { Ge = 0.0; if (elecvis) { Ge = -(0.73 * Te * Ne * tau_e) - * (2. * Grad_par(Ve) + (5. * C(Te) + 5. * Te * C(logNe) + C(phi)) / coords->Bxy); + * (2. * Grad_par(Ve) + + (5. * C(Te) + 5. * Te * C(logNe) + C(phi)) / coords->Bxy()); mesh->communicate(Ge); Ge.applyBoundary("neumann"); } else { @@ -443,8 +445,8 @@ int GBS::rhs(BoutReal t) { if (evolve_Ne) { // Density - ddt(Ne) = -vE_Grad(Ne, phi) // ExB term - + (2. / coords->Bxy) * (C(Pe) - Ne * C(phi)) // Perpendicular compression + ddt(Ne) = -vE_Grad(Ne, phi) // ExB term + + (2. / coords->Bxy()) * (C(Pe) - Ne * C(phi)) // Perpendicular compression + D(Ne, Dn) + H(Ne, Hn); if (parallel) { @@ -461,7 +463,7 @@ int GBS::rhs(BoutReal t) { if (evolve_Te) { // Electron temperature ddt(Te) = -vE_Grad(Te, phi) - + (4. / 3.) * (Te / coords->Bxy) + + (4. / 3.) * (Te / coords->Bxy()) * ((7. / 2.) * C(Te) + (Te / Ne) * C(Ne) - C(phi)) + D(Te, Dte) + H(Te, Hte); @@ -485,14 +487,14 @@ int GBS::rhs(BoutReal t) { if (evolve_Vort) { // Vorticity ddt(Vort) = -vE_Grad(Vort, phi) // ExB term - + 2. * coords->Bxy * C(Pe) / Ne + coords->Bxy * C(Gi) / (3. * Ne) + + 2. * coords->Bxy() * C(Pe) / Ne + coords->Bxy() * C(Gi) / (3. * Ne) + D(Vort, Dvort) + H(Vort, Hvort); if (parallel) { Field3D delV = Vi - Ve; mesh->communicate(delV); ddt(Vort) -= Vpar_Grad_par(Vi, Vort); // Parallel advection - ddt(Vort) += SQ(coords->Bxy) * (Grad_par(delV) + (Vi - Ve) * Grad_par(logNe)); + ddt(Vort) += SQ(coords->Bxy()) * (Grad_par(delV) + (Vi - Ve) * Grad_par(logNe)); } } @@ -528,7 +530,7 @@ const Field3D GBS::C(const Field3D& f) { // Curvature operator mesh->communicate(g); return bxcv * Grad(g); } - return coords->Bxy * bracket(logB, f, BRACKET_ARAKAWA); + return coords->Bxy() * bracket(logB, f, BRACKET_ARAKAWA); } const Field3D GBS::D(const Field3D& f, BoutReal d) { // Diffusion operator diff --git a/tests/MMS/GBS/gbs.hxx b/tests/MMS/GBS/gbs.hxx index 468a5e579c..da7a971389 100644 --- a/tests/MMS/GBS/gbs.hxx +++ b/tests/MMS/GBS/gbs.hxx @@ -88,8 +88,9 @@ private: const Field3D D(const Field3D& f, BoutReal d); // Diffusion operator const Field3D H(const Field3D& f, BoutReal h); // Hyper-diffusion // Powers of the mesh spacing for H operator - Field2D dx4, dy4; - BoutReal dz4; + Field2D dx4; + Field2D dy4; + Field2D dz4; // Laplacian solver std::unique_ptr phiSolver{nullptr}; diff --git a/tests/MMS/advection/advection.cxx b/tests/MMS/advection/advection.cxx index 1201fbc3ac..6b8510ec83 100644 --- a/tests/MMS/advection/advection.cxx +++ b/tests/MMS/advection/advection.cxx @@ -18,8 +18,8 @@ class AdvectMMS : public PhysicsModel { Coordinates* coords = mesh->getCoordinates(); - dx_sq_sq = SQ(SQ(coords->dx)); - dz_sq_sq = SQ(SQ(coords->dz)); + dx_sq_sq = SQ(SQ(coords->dx())); + dz_sq_sq = SQ(SQ(coords->dz())); return 0; } diff --git a/tests/MMS/diffusion/diffusion.cxx b/tests/MMS/diffusion/diffusion.cxx index bd969d4d86..d0e8ed7641 100644 --- a/tests/MMS/diffusion/diffusion.cxx +++ b/tests/MMS/diffusion/diffusion.cxx @@ -32,8 +32,8 @@ int Diffusion::init(bool UNUSED(restarting)) { /*this assumes equidistant grid*/ int nguard = mesh->xstart; - coord->dx = Lx / (mesh->GlobalNx - 2 * nguard); - coord->dy = Ly / (mesh->GlobalNy - 2 * nguard); + coord->setDx(Lx / (mesh->GlobalNx - 2 * nguard)); + coord->setDy(Ly / (mesh->GlobalNy - 2 * nguard)); SAVE_ONCE2(Lx, Ly); @@ -43,20 +43,10 @@ int Diffusion::init(bool UNUSED(restarting)) { SAVE_ONCE(mu_N); //set mesh - coord->g11 = 1.0; - coord->g22 = 1.0; - coord->g33 = 1.0; - coord->g12 = 0.0; - coord->g13 = 0.0; - coord->g23 = 0.0; - - coord->g_11 = 1.0; - coord->g_22 = 1.0; - coord->g_33 = 1.0; - coord->g_12 = 0.0; - coord->g_13 = 0.0; - coord->g_23 = 0.0; - coord->geometry(); + auto contravariant_metric_tensor = + ContravariantMetricTensor(1.1, 1.1, 1.1, 0.0, 0.0, 0.0); + auto covariant_metric_tensor = CovariantMetricTensor(1.1, 1.1, 1.1, 0.0, 0.0, 0.0); + coord->setMetricTensor(contravariant_metric_tensor, covariant_metric_tensor); // Tell BOUT++ to solve N SOLVE_FOR(N); diff --git a/tests/MMS/diffusion2/diffusion.cxx b/tests/MMS/diffusion2/diffusion.cxx index bd2cd72a08..cb94719c44 100644 --- a/tests/MMS/diffusion2/diffusion.cxx +++ b/tests/MMS/diffusion2/diffusion.cxx @@ -21,9 +21,9 @@ class Diffusion : public PhysicsModel { meshoptions->get("Ly", Ly, 1.0); /*this assumes equidistant grid*/ - coords->dx = Lx / (mesh->GlobalNx - 2 * mesh->xstart); + coords->setDx(Lx / (mesh->GlobalNx - 2 * mesh->xstart)); - coords->dy = Ly / (mesh->GlobalNy - 2 * mesh->ystart); + coords->setDy(Ly / (mesh->GlobalNy - 2 * mesh->ystart)); output.write("SIZES: {:d}, {:d}, {:e}\n", mesh->GlobalNy, (mesh->GlobalNy - 2 * mesh->ystart), coords->dy(0, 0, 0)); @@ -38,20 +38,10 @@ class Diffusion : public PhysicsModel { SAVE_ONCE3(Dx, Dy, Dz); // set mesh - coords->g11 = 1.0; - coords->g22 = 1.0; - coords->g33 = 1.0; - coords->g12 = 0.0; - coords->g13 = 0.0; - coords->g23 = 0.0; - - coords->g_11 = 1.0; - coords->g_22 = 1.0; - coords->g_33 = 1.0; - coords->g_12 = 0.0; - coords->g_13 = 0.0; - coords->g_23 = 0.0; - coords->geometry(); + auto contravariant_metric_tensor = + ContravariantMetricTensor(1.1, 1.1, 1.1, 0.0, 0.0, 0.0); + auto covariant_metric_tensor = CovariantMetricTensor(1.1, 1.1, 1.1, 0.0, 0.0, 0.0); + coords->setMetricTensor(contravariant_metric_tensor, covariant_metric_tensor); // Tell BOUT++ to solve N SOLVE_FOR(N); diff --git a/tests/MMS/elm-pb/elm_pb.cxx b/tests/MMS/elm-pb/elm_pb.cxx index 3ad8f70b85..851b2d2a69 100644 --- a/tests/MMS/elm-pb/elm_pb.cxx +++ b/tests/MMS/elm-pb/elm_pb.cxx @@ -314,7 +314,7 @@ class ELMpb : public PhysicsModel { if (ShiftXderivs) { if (mesh->IncIntShear) { // BOUT-06 style, using d/dx = d/dpsi + I * d/dz - coords->IntShiftTorsion = I; + coords->setIntShiftTorsion(I); } else { // Dimits style, using local coordinate system @@ -389,7 +389,7 @@ class ELMpb : public PhysicsModel { Btxy /= Bbar; B0 /= Bbar; hthe /= Lbar; - coords->dx /= Lbar * Lbar * Bbar; + coords->setDx(coords->dx() / (Lbar * Lbar * Bbar)); I *= Lbar * Lbar * Bbar; BoutReal pnorm = max(P0, true); // Maximum over all processors @@ -417,24 +417,25 @@ class ELMpb : public PhysicsModel { /**************** CALCULATE METRICS ******************/ - coords->g11 = SQ(Rxy * Bpxy); - coords->g22 = 1.0 / SQ(hthe); - coords->g33 = SQ(I) * coords->g11 + SQ(B0) / coords->g11; - coords->g12 = 0.0; - coords->g13 = -I * coords->g11; - coords->g23 = -Btxy / (hthe * Bpxy * Rxy); + const auto g11 = SQ(Rxy * Bpxy); + const auto g22 = 1.0 / SQ(hthe); + const auto g33 = SQ(I) * g11 + SQ(B0) / g11; + const auto g12 = 0.0; + const auto g13 = -I * g11; + const auto g23 = -Btxy / (hthe * Bpxy * Rxy); - coords->J = hthe / Bpxy; - coords->Bxy = B0; + const auto g_11 = 1.0 / g11 + (SQ(I * Rxy)); + const auto g_22 = SQ(B0 * hthe / Bpxy); + const auto g_33 = Rxy * Rxy; + const auto g_12 = Btxy * hthe * I * Rxy / Bpxy; + const auto g_13 = I * Rxy * Rxy; + const auto g_23 = Btxy * hthe * Rxy / Bpxy; - coords->g_11 = 1.0 / coords->g11 + (SQ(I * Rxy)); - coords->g_22 = SQ(B0 * hthe / Bpxy); - coords->g_33 = Rxy * Rxy; - coords->g_12 = Btxy * hthe * I * Rxy / Bpxy; - coords->g_13 = I * Rxy * Rxy; - coords->g_23 = Btxy * hthe * Rxy / Bpxy; + coords->setMetricTensor(ContravariantMetricTensor(g11, g22, g33, g12, g13, g23), + CovariantMetricTensor(g_11, g_22, g_33, g_12, g_13, g_23)); - coords->geometry(); // Calculate quantities from metric tensor + coords->setJ(hthe / Bpxy); + coords->setBxy(B0); // Set B field vector @@ -634,7 +635,7 @@ class ELMpb : public PhysicsModel { ddt(U) += viscos_perp * Delp2(U); // Perpendicular viscosity } - ddt(U) -= 10 * (SQ(SQ(coords->dx)) * D4DX4(U) + SQ(SQ(coords->dz)) * D4DZ4(U)); + ddt(U) -= 10 * (SQ(SQ(coords->dx())) * D4DX4(U) + SQ(SQ(coords->dz())) * D4DZ4(U)); //////////////////////////////////////////////////// // Pressure equation @@ -654,7 +655,7 @@ class ELMpb : public PhysicsModel { ddt(P) += diffusion_par * Grad2_par2(P); // Parallel diffusion } - ddt(P) -= 10 * (SQ(SQ(coords->dx)) * D4DX4(P) + SQ(SQ(coords->dz)) * D4DZ4(P)); + ddt(P) -= 10 * (SQ(SQ(coords->dx())) * D4DX4(P) + SQ(SQ(coords->dz())) * D4DZ4(P)); //////////////////////////////////////////////////// // Compressional effects diff --git a/tests/MMS/fieldalign/fieldalign.cxx b/tests/MMS/fieldalign/fieldalign.cxx index 75481dee9a..16e9c50bc8 100644 --- a/tests/MMS/fieldalign/fieldalign.cxx +++ b/tests/MMS/fieldalign/fieldalign.cxx @@ -20,14 +20,16 @@ class FieldAlign : public PhysicsModel { // df/dt = df/dtheta + df/dphi ddt(f) = - vx / G * (metric->g11 * DDX(f) + metric->g12 * DDY(f) + metric->g13 * DDZ(f)) - + vy / G * (metric->g12 * DDX(f) + metric->g22 * DDY(f) + metric->g23 * DDZ(f)) + vx / G + * (metric->g11() * DDX(f) + metric->g12() * DDY(f) + metric->g13() * DDZ(f)) + + vy / G + * (metric->g12() * DDX(f) + metric->g22() * DDY(f) + metric->g23() * DDZ(f)) + // Upwinding with second-order central differencing vz / G - * (metric->g13 * DDX(f) + metric->g23 * DDY(f) - + metric->g33 * DDZ(f)); // (unstable without additional dissipation) - -SQ(SQ(metric->dx)) * D4DX4(f) /*- SQ(SQ(metric->dy))*D4DY4(f)*/ - - SQ(SQ(metric->dz)) * D4DZ4(f); // Numerical dissipation terms + * (metric->g13() * DDX(f) + metric->g23() * DDY(f) + + metric->g33() * DDZ(f)); // (unstable without additional dissipation) + -SQ(SQ(metric->dx())) * D4DX4(f) /*- SQ(SQ(metric->dy()))*D4DY4(f)*/ + - SQ(SQ(metric->dz())) * D4DZ4(f); // Numerical dissipation terms return 0; } diff --git a/tests/MMS/hw/hw.cxx b/tests/MMS/hw/hw.cxx index c5dd25773f..c51e17ab14 100644 --- a/tests/MMS/hw/hw.cxx +++ b/tests/MMS/hw/hw.cxx @@ -39,8 +39,8 @@ class Hw : public PhysicsModel { /*this assumes equidistant grid*/ int nguard = mesh->xstart; - mesh->getCoordinates()->dx = Lx / (mesh->GlobalNx - 2 * nguard); - mesh->getCoordinates()->dz = TWOPI * Lx / (mesh->LocalNz); + mesh->getCoordinates()->setDx(Lx / (mesh->GlobalNx - 2 * nguard)); + mesh->getCoordinates()->setDz(TWOPI * Lx / (mesh->LocalNz)); ///// SOLVE_FOR2(n, vort); diff --git a/tests/MMS/laplace/laplace.cxx b/tests/MMS/laplace/laplace.cxx index 54dbaaba67..475725f269 100644 --- a/tests/MMS/laplace/laplace.cxx +++ b/tests/MMS/laplace/laplace.cxx @@ -22,8 +22,8 @@ int main(int argc, char** argv) { /*this assumes equidistant grid*/ int nguard = mesh->xstart; - mesh->getCoordinates()->dx = Lx / (mesh->GlobalNx - 2 * nguard); - mesh->getCoordinates()->dz = TWOPI * Lx / (mesh->LocalNz); + mesh->getCoordinates()->setDx(Lx / (mesh->GlobalNx - 2 * nguard)); + mesh->getCoordinates()->setDz(TWOPI * Lx / (mesh->LocalNz)); ///// // Create a Laplacian inversion solver diff --git a/tests/MMS/spatial/diffusion/diffusion.cxx b/tests/MMS/spatial/diffusion/diffusion.cxx index 45e516751a..918dcd79cb 100644 --- a/tests/MMS/spatial/diffusion/diffusion.cxx +++ b/tests/MMS/spatial/diffusion/diffusion.cxx @@ -22,37 +22,27 @@ class Diffusion : public PhysicsModel { meshoptions->get("Ly", Ly, 1.0); /*this assumes equidistant grid*/ - coords->dx = Lx / (mesh->GlobalNx - 2 * mesh->xstart); + coords->setDx(Lx / (mesh->GlobalNx - 2 * mesh->xstart)); - coords->dy = Ly / (mesh->GlobalNy - 2 * mesh->ystart); + coords->setDy(Ly / (mesh->GlobalNy - 2 * mesh->ystart)); output.write("SIZES: {:d}, {:d}, {:e}\n", mesh->GlobalNy, (mesh->GlobalNy - 2 * mesh->ystart), coords->dy(0, 0, 0)); - SAVE_ONCE2(Lx, Ly); + SAVE_ONCE2(Lx, Ly) Options* cytooptions = Options::getRoot()->getSection("cyto"); OPTION(cytooptions, Dx, 1.0); OPTION(cytooptions, Dy, -1.0); OPTION(cytooptions, Dz, -1.0); - SAVE_ONCE3(Dx, Dy, Dz); + SAVE_ONCE3(Dx, Dy, Dz) // set mesh - coords->g11 = 1.0; - coords->g22 = 1.0; - coords->g33 = 1.0; - coords->g12 = 0.0; - coords->g13 = 0.0; - coords->g23 = 0.0; - - coords->g_11 = 1.0; - coords->g_22 = 1.0; - coords->g_33 = 1.0; - coords->g_12 = 0.0; - coords->g_13 = 0.0; - coords->g_23 = 0.0; - coords->geometry(); + auto contravariant_metric_tensor = + ContravariantMetricTensor(1.1, 1.1, 1.1, 0.0, 0.0, 0.0); + auto covariant_metric_tensor = CovariantMetricTensor(1.1, 1.1, 1.1, 0.0, 0.0, 0.0); + coords->setMetricTensor(contravariant_metric_tensor, covariant_metric_tensor); // Tell BOUT++ to solve N SOLVE_FOR(N); diff --git a/tests/MMS/tokamak/tokamak.cxx b/tests/MMS/tokamak/tokamak.cxx index a8bf4b685e..74c89bb95d 100644 --- a/tests/MMS/tokamak/tokamak.cxx +++ b/tests/MMS/tokamak/tokamak.cxx @@ -31,8 +31,8 @@ class TokamakMMS : public PhysicsModel { // Test bracket advection operator ddt(advect) = -1e-3 * bracket(drive, advect, BRACKET_ARAKAWA) - 10. - * (SQ(SQ(mesh->getCoordinates()->dx)) * D4DX4(advect) - + SQ(SQ(mesh->getCoordinates()->dz)) * D4DZ4(advect)); + * (SQ(SQ(mesh->getCoordinates()->dx())) * D4DX4(advect) + + SQ(SQ(mesh->getCoordinates()->dz())) * D4DZ4(advect)); // Test perpendicular diffusion operator ddt(delp2) = 1e-5 * Delp2(delp2); @@ -53,7 +53,7 @@ class TokamakMMS : public PhysicsModel { Field2D dx; if (!mesh->get(dx, "dpsi")) { output << "\tUsing dpsi as the x grid spacing\n"; - coords->dx = dx; // Only use dpsi if found + coords->setDx(dx); // Only use dpsi if found } else { // dx will have been read already from the grid output << "\tUsing dx as the x grid spacing\n"; @@ -62,11 +62,11 @@ class TokamakMMS : public PhysicsModel { Rxy /= Lnorm; hthe /= Lnorm; sinty *= SQ(Lnorm) * Bnorm; - coords->dx /= SQ(Lnorm) * Bnorm; + coords->setDx(coords->dx() / (SQ(Lnorm) * Bnorm)); Bpxy /= Bnorm; Btxy /= Bnorm; - coords->Bxy /= Bnorm; + coords->setBxy(coords->Bxy() / Bnorm); // Calculate metric components bool ShiftXderivs; @@ -80,23 +80,24 @@ class TokamakMMS : public PhysicsModel { sbp = -1.0; } - coords->g11 = SQ(Rxy * Bpxy); - coords->g22 = 1.0 / SQ(hthe); - coords->g33 = SQ(sinty) * coords->g11 + SQ(coords->Bxy) / coords->g11; - coords->g12 = 0.0; - coords->g13 = -sinty * coords->g11; - coords->g23 = -sbp * Btxy / (hthe * Bpxy * Rxy); + const auto g11 = SQ(Rxy * Bpxy); + const auto g22 = 1.0 / SQ(hthe); + const auto g33 = SQ(sinty) * g11 + SQ(coords->Bxy()) / g11; + const auto g12 = 0.0; + const auto g13 = -sinty * g11; + const auto g23 = -sbp * Btxy / (hthe * Bpxy * Rxy); - coords->J = hthe / Bpxy; + const auto g_11 = 1.0 / g11 + SQ(sinty * Rxy); + const auto g_22 = SQ(coords->Bxy() * hthe / Bpxy); + const auto g_33 = Rxy * Rxy; + const auto g_12 = sbp * Btxy * hthe * sinty * Rxy / Bpxy; + const auto g_13 = sinty * Rxy * Rxy; + const auto g_23 = sbp * Btxy * hthe * Rxy / Bpxy; - coords->g_11 = 1.0 / coords->g11 + SQ(sinty * Rxy); - coords->g_22 = SQ(coords->Bxy * hthe / Bpxy); - coords->g_33 = Rxy * Rxy; - coords->g_12 = sbp * Btxy * hthe * sinty * Rxy / Bpxy; - coords->g_13 = sinty * Rxy * Rxy; - coords->g_23 = sbp * Btxy * hthe * Rxy / Bpxy; + coords->setMetricTensor(ContravariantMetricTensor(g11, g22, g33, g12, g13, g23), + CovariantMetricTensor(g_11, g_22, g_33, g_12, g_13, g_23)); - coords->geometry(); + coords->setJ(hthe / Bpxy); } private: diff --git a/tests/MMS/wave-1d/wave.cxx b/tests/MMS/wave-1d/wave.cxx index 4f53d098c6..92689b9b2f 100644 --- a/tests/MMS/wave-1d/wave.cxx +++ b/tests/MMS/wave-1d/wave.cxx @@ -26,26 +26,16 @@ class Wave1D : public PhysicsModel { // this assumes equidistant grid int nguard = mesh->xstart; - coord->dx = Lx / (mesh->GlobalNx - 2 * nguard); - coord->dy = Ly / (mesh->GlobalNy - 2 * nguard); + coord->setDx(Lx / (mesh->GlobalNx - 2 * nguard)); + coord->setDy(Ly / (mesh->GlobalNy - 2 * nguard)); SAVE_ONCE(Lx, Ly); //set mesh - coord->g11 = 1.0; - coord->g22 = 1.0; - coord->g33 = 1.0; - coord->g12 = 0.0; - coord->g13 = 0.0; - coord->g23 = 0.0; - - coord->g_11 = 1.0; - coord->g_22 = 1.0; - coord->g_33 = 1.0; - coord->g_12 = 0.0; - coord->g_13 = 0.0; - coord->g_23 = 0.0; - coord->geometry(); + auto contravariant_metric_tensor = + ContravariantMetricTensor(1.1, 1.1, 1.1, 0.0, 0.0, 0.0); + auto covariant_metric_tensor = CovariantMetricTensor(1.1, 1.1, 1.1, 0.0, 0.0, 0.0); + coord->setMetricTensor(contravariant_metric_tensor, covariant_metric_tensor); g.setLocation(CELL_XLOW); // g staggered to the left of f @@ -63,8 +53,8 @@ class Wave1D : public PhysicsModel { g.applyBoundary(t); // Central differencing - ddt(f) = DDX(g, CELL_CENTRE); // + 20*SQ(coord->dx)*D2DX2(f); - ddt(g) = DDX(f, CELL_XLOW); // + 20*SQ(coord->dx)*D2DX2(g); + ddt(f) = DDX(g, CELL_CENTRE); // + 20*SQ(coord->dx())*D2DX2(f); + ddt(g) = DDX(f, CELL_XLOW); // + 20*SQ(coord->dx())*D2DX2(g); return 0; } diff --git a/tests/integrated/test-drift-instability/2fluid.cxx b/tests/integrated/test-drift-instability/2fluid.cxx index 89105e970c..f7b072cae5 100644 --- a/tests/integrated/test-drift-instability/2fluid.cxx +++ b/tests/integrated/test-drift-instability/2fluid.cxx @@ -16,7 +16,7 @@ #include // just define a macro for V_E dot Grad -#define vE_Grad(f, p) (b0xGrad_dot_Grad(p, f) / coord->Bxy) +#define vE_Grad(f, p) (b0xGrad_dot_Grad(p, f) / coord->Bxy()) class TwoFluid : public PhysicsModel { // 2D initial profiles @@ -96,7 +96,7 @@ class TwoFluid : public PhysicsModel { GRID_LOAD(Bpxy); GRID_LOAD(Btxy); GRID_LOAD(hthe); - mesh->get(coord->dx, "dpsi"); + coord->setDx(mesh->get("dpsi")); mesh->get(I, "sinty"); // Load normalisation values @@ -204,12 +204,12 @@ class TwoFluid : public PhysicsModel { Rxy /= rho_s; hthe /= rho_s; I *= rho_s * rho_s * (bmag / 1e4) * ShearFactor; - coord->dx /= rho_s * rho_s * (bmag / 1e4); + coord->setDx(coord->dx() / (rho_s * rho_s * (bmag / 1e4))); // Normalise magnetic field Bpxy /= (bmag / 1.e4); Btxy /= (bmag / 1.e4); - coord->Bxy /= (bmag / 1.e4); + coord->setBxy(coord->Bxy() / (bmag / 1.e4)); // calculate pressures pei0 = (Ti0 + Te0) * Ni0; @@ -217,23 +217,24 @@ class TwoFluid : public PhysicsModel { /**************** CALCULATE METRICS ******************/ - coord->g11 = SQ(Rxy * Bpxy); - coord->g22 = 1.0 / SQ(hthe); - coord->g33 = SQ(I) * coord->g11 + SQ(coord->Bxy) / coord->g11; - coord->g12 = 0.0; - coord->g13 = -I * coord->g11; - coord->g23 = -Btxy / (hthe * Bpxy * Rxy); + const auto g11 = SQ(Rxy * Bpxy); + const auto g22 = 1.0 / SQ(hthe); + const auto g33 = SQ(I) * g11 + SQ(coord->Bxy()) / g11; + const auto g12 = 0.0; + const auto g13 = -I * g11; + const auto g23 = -Btxy / (hthe * Bpxy * Rxy); - coord->J = hthe / Bpxy; + const auto g_11 = 1.0 / g11 + SQ(I * Rxy); + const auto g_22 = SQ(coord->Bxy() * hthe / Bpxy); + const auto g_33 = Rxy * Rxy; + const auto g_12 = Btxy * hthe * I * Rxy / Bpxy; + const auto g_13 = I * Rxy * Rxy; + const auto g_23 = Btxy * hthe * Rxy / Bpxy; - coord->g_11 = 1.0 / coord->g11 + SQ(I * Rxy); - coord->g_22 = SQ(coord->Bxy * hthe / Bpxy); - coord->g_33 = Rxy * Rxy; - coord->g_12 = Btxy * hthe * I * Rxy / Bpxy; - coord->g_13 = I * Rxy * Rxy; - coord->g_23 = Btxy * hthe * Rxy / Bpxy; + coord->setMetricTensor(ContravariantMetricTensor(g11, g22, g33, g12, g13, g23), + CovariantMetricTensor(g_11, g_22, g_33, g_12, g_13, g_23)); - coord->geometry(); + coord->setJ(hthe / Bpxy); /**************** SET EVOLVING VARIABLES *************/ @@ -411,7 +412,7 @@ class TwoFluid : public PhysicsModel { if (evolve_rho) { auto divPar_jpar_ylow = Div_par(jpar); mesh->communicate(divPar_jpar_ylow); - ddt(rho) += SQ(coord->Bxy) * interp_to(divPar_jpar_ylow, CELL_CENTRE); + ddt(rho) += SQ(coord->Bxy()) * interp_to(divPar_jpar_ylow, CELL_CENTRE); } // AJPAR diff --git a/tests/integrated/test-interchange-instability/2fluid.cxx b/tests/integrated/test-interchange-instability/2fluid.cxx index 5e57e166c4..cddc81e91c 100644 --- a/tests/integrated/test-interchange-instability/2fluid.cxx +++ b/tests/integrated/test-interchange-instability/2fluid.cxx @@ -64,7 +64,7 @@ class Interchange : public PhysicsModel { GRID_LOAD(Bpxy); GRID_LOAD(Btxy); GRID_LOAD(hthe); - mesh->get(coord->dx, "dpsi"); + coord->setDx(mesh->get("dpsi")); mesh->get(I, "sinty"); // Load normalisation values @@ -130,32 +130,33 @@ class Interchange : public PhysicsModel { Rxy /= rho_s; hthe /= rho_s; I *= rho_s * rho_s * (bmag / 1e4) * ShearFactor; - coord->dx /= rho_s * rho_s * (bmag / 1e4); + coord->setDx(coord->dx() / (rho_s * rho_s * (bmag / 1e4))); // Normalise magnetic field Bpxy /= (bmag / 1.e4); Btxy /= (bmag / 1.e4); - coord->Bxy /= (bmag / 1.e4); + coord->setBxy(coord->Bxy() / (bmag / 1.e4)); /**************** CALCULATE METRICS ******************/ - coord->g11 = SQ(Rxy * Bpxy); - coord->g22 = 1.0 / SQ(hthe); - coord->g33 = SQ(I) * coord->g11 + SQ(coord->Bxy) / coord->g11; - coord->g12 = 0.0; - coord->g13 = -I * coord->g11; - coord->g23 = -Btxy / (hthe * Bpxy * Rxy); + const auto g11 = SQ(Rxy * Bpxy); + const auto g22 = 1.0 / SQ(hthe); + const auto g33 = SQ(I) * g11 + SQ(coord->Bxy()) / g11; + const auto g12 = 0.0; + const auto g13 = -I * g11; + const auto g23 = -Btxy / (hthe * Bpxy * Rxy); - coord->J = hthe / Bpxy; + const auto g_11 = 1.0 / g11 + SQ(I * Rxy); + const auto g_22 = SQ(coord->Bxy() * hthe / Bpxy); + const auto g_33 = Rxy * Rxy; + const auto g_12 = Btxy * hthe * I * Rxy / Bpxy; + const auto g_13 = I * Rxy * Rxy; + const auto g_23 = Btxy * hthe * Rxy / Bpxy; - coord->g_11 = 1.0 / coord->g11 + SQ(I * Rxy); - coord->g_22 = SQ(coord->Bxy * hthe / Bpxy); - coord->g_33 = Rxy * Rxy; - coord->g_12 = Btxy * hthe * I * Rxy / Bpxy; - coord->g_13 = I * Rxy * Rxy; - coord->g_23 = Btxy * hthe * Rxy / Bpxy; + coord->setMetricTensor(ContravariantMetricTensor(g11, g22, g33, g12, g13, g23), + CovariantMetricTensor(g_11, g_22, g_33, g_12, g_13, g_23)); - coord->geometry(); + coord->setJ(hthe / Bpxy); // Tell BOUT++ which variables to evolve SOLVE_FOR2(rho, Ni); @@ -180,10 +181,10 @@ class Interchange : public PhysicsModel { Field3D pei = (Te0 + Ti0) * Ni; // DENSITY EQUATION - ddt(Ni) = -b0xGrad_dot_Grad(phi, Ni0) / coord->Bxy; + ddt(Ni) = -b0xGrad_dot_Grad(phi, Ni0) / coord->Bxy(); // VORTICITY - ddt(rho) = 2.0 * coord->Bxy * b0xcv * Grad(pei); + ddt(rho) = 2.0 * coord->Bxy() * b0xcv * Grad(pei); return (0); } diff --git a/tests/integrated/test-laplacexy-short/test-laplacexy.cxx b/tests/integrated/test-laplacexy-short/test-laplacexy.cxx index 3486760810..baa9b21264 100644 --- a/tests/integrated/test-laplacexy-short/test-laplacexy.cxx +++ b/tests/integrated/test-laplacexy-short/test-laplacexy.cxx @@ -65,8 +65,8 @@ int main(int argc, char** argv) { if (include_y_derivs) { rhs = a * DC(Laplace_perp(f)) + DC(Grad_perp(a) * Grad_perp(f)) + b * f; } else { - rhs = - a * DC(Delp2(f, CELL_DEFAULT, false)) + DC(coords->g11 * DDX(a) * DDX(f)) + b * f; + rhs = a * DC(Delp2(f, CELL_DEFAULT, false)) + DC(coords->g11() * DDX(a) * DDX(f)) + + b * f; } laplacexy.setCoefs(a, b); @@ -83,7 +83,7 @@ int main(int argc, char** argv) { rhs_check = a * DC(Laplace_perp(sol)) + DC(Grad_perp(a) * Grad_perp(sol)) + b * sol; } else { rhs_check = a * DC(Delp2(sol, CELL_DEFAULT, false)) - + DC(coords->g11 * DDX(a) * DDX(sol)) + b * sol; + + DC(coords->g11() * DDX(a) * DDX(sol)) + b * sol; } Options dump; diff --git a/tests/integrated/test-laplacexy/loadmetric.cxx b/tests/integrated/test-laplacexy/loadmetric.cxx index 6d8afad750..3fccd4acce 100644 --- a/tests/integrated/test-laplacexy/loadmetric.cxx +++ b/tests/integrated/test-laplacexy/loadmetric.cxx @@ -19,7 +19,7 @@ void LoadMetric(BoutReal Lnorm, BoutReal Bnorm) { Field2D dx; if (!mesh->get(dx, "dpsi")) { output << "\tUsing dpsi as the x grid spacing\n"; - coords->dx = dx; // Only use dpsi if found + coords->setDx(dx); // Only use dpsi if found } else { // dx will have been read already from the grid output << "\tUsing dx as the x grid spacing\n"; @@ -29,11 +29,11 @@ void LoadMetric(BoutReal Lnorm, BoutReal Bnorm) { Rxy /= Lnorm; hthe /= Lnorm; sinty *= SQ(Lnorm) * Bnorm; - coords->dx /= SQ(Lnorm) * Bnorm; + coords->setDx(coords->dx() / (SQ(Lnorm) * Bnorm)); Bpxy /= Bnorm; Btxy /= Bnorm; - coords->Bxy /= Bnorm; + coords->setBxy(coords->Bxy() / Bnorm); // Calculate metric components std::string ptstr; @@ -49,21 +49,22 @@ void LoadMetric(BoutReal Lnorm, BoutReal Bnorm) { sbp = -1.0; } - coords->g11 = pow(Rxy * Bpxy, 2); - coords->g22 = 1.0 / pow(hthe, 2); - coords->g33 = pow(sinty, 2) * coords->g11 + pow(coords->Bxy, 2) / coords->g11; - coords->g12 = 0.0; - coords->g13 = -sinty * coords->g11; - coords->g23 = -sbp * Btxy / (hthe * Bpxy * Rxy); + const auto g11 = pow(Rxy * Bpxy, 2); + const auto g22 = 1.0 / pow(hthe, 2); + const auto g33 = pow(sinty, 2) * g11 + pow(coords->Bxy(), 2) / g11; + const auto g12 = 0.0; + const auto g13 = -sinty * g11; + const auto g23 = -sbp * Btxy / (hthe * Bpxy * Rxy); - coords->J = hthe / Bpxy; + const auto g_11 = 1.0 / g11 + pow(sinty * Rxy, 2); + const auto g_22 = pow(coords->Bxy() * hthe / Bpxy, 2); + const auto g_33 = Rxy * Rxy; + const auto g_12 = sbp * Btxy * hthe * sinty * Rxy / Bpxy; + const auto g_13 = sinty * Rxy * Rxy; + const auto g_23 = sbp * Btxy * hthe * Rxy / Bpxy; - coords->g_11 = 1.0 / coords->g11 + pow(sinty * Rxy, 2); - coords->g_22 = pow(coords->Bxy * hthe / Bpxy, 2); - coords->g_33 = Rxy * Rxy; - coords->g_12 = sbp * Btxy * hthe * sinty * Rxy / Bpxy; - coords->g_13 = sinty * Rxy * Rxy; - coords->g_23 = sbp * Btxy * hthe * Rxy / Bpxy; + coords->setMetricTensor(ContravariantMetricTensor(g11, g22, g33, g12, g13, g23), + CovariantMetricTensor(g_11, g_22, g_33, g_12, g_13, g_23)); - coords->geometry(); + coords->setJ(hthe / Bpxy); } diff --git a/tests/integrated/test-laplacexy/test-laplacexy.cxx b/tests/integrated/test-laplacexy/test-laplacexy.cxx index 3142d359b1..b5deb38ce1 100644 --- a/tests/integrated/test-laplacexy/test-laplacexy.cxx +++ b/tests/integrated/test-laplacexy/test-laplacexy.cxx @@ -61,7 +61,7 @@ int main(int argc, char** argv) { if (include_y_derivs) { rhs = a * Laplace_perp(f) + Grad_perp(a) * Grad_perp(f) + b * f; } else { - rhs = a * Delp2(f, CELL_DEFAULT, false) + coords->g11 * DDX(a) * DDX(f) + b * f; + rhs = a * Delp2(f, CELL_DEFAULT, false) + coords->g11() * DDX(a) * DDX(f) + b * f; } LaplaceXY laplacexy; @@ -81,7 +81,7 @@ int main(int argc, char** argv) { a * Laplace_perp(solution) + Grad_perp(a) * Grad_perp(solution) + b * solution; } else { rhs_check = a * Delp2(solution, CELL_DEFAULT, false) - + coords->g11 * DDX(a) * DDX(solution) + b * solution; + + coords->g11() * DDX(a) * DDX(solution) + b * solution; } Options dump; diff --git a/tests/integrated/test-laplacexy2-hypre/CMakeLists.txt b/tests/integrated/test-laplacexy2-hypre/CMakeLists.txt index a787752ebc..6a719bfe7f 100644 --- a/tests/integrated/test-laplacexy2-hypre/CMakeLists.txt +++ b/tests/integrated/test-laplacexy2-hypre/CMakeLists.txt @@ -1,6 +1,7 @@ bout_add_integrated_test(test-laplacexy2-hypre SOURCES test-laplacexy.cxx REQUIRES BOUT_HAS_HYPRE + CONFLICTS BOUT_USE_METRIC_3D USE_RUNTEST USE_DATA_BOUT_INP ) diff --git a/tests/integrated/test-laplacexz/test-laplacexz.cxx b/tests/integrated/test-laplacexz/test-laplacexz.cxx index 6e43d2f3f7..1b3d22b2b1 100644 --- a/tests/integrated/test-laplacexz/test-laplacexz.cxx +++ b/tests/integrated/test-laplacexz/test-laplacexz.cxx @@ -20,19 +20,24 @@ int main(int argc, char** argv) { auto inv = LaplaceXZ::create(bout::globals::mesh); auto coord = bout::globals::mesh->getCoordinates(); - coord->g13 = 1.8; // test off-diagonal components with nonzero value + const auto g13 = 0.8; // test off-diagonal components with nonzero value + coord->setContravariantMetricTensor(ContravariantMetricTensor( + coord->g11(), coord->g22(), coord->g33(), coord->g12(), g13, coord->g23())); // create some input field Field3D f = FieldFactory::get()->create3D("f", Options::getRoot(), bout::globals::mesh); // Calculate the Laplacian with non-zero g13 - Field3D g = coord->g11 * D2DX2(f) + coord->g13 * D2DXDZ(f) + coord->g33 * D2DZ2(f); + const Field3D g = + coord->g11() * D2DX2(f) + coord->g13() * D2DXDZ(f) + coord->g33() * D2DZ2(f); inv->setCoefs(Field2D(1.0), Field2D(0.0)); Field3D f2 = inv->solve(g, 0.0); // Invert the Laplacian. - coord->g13 = 0.0; // reset to 0.0 for original laplacexz test + // reset to 0.0 for original laplacexz test + coord->setContravariantMetricTensor(ContravariantMetricTensor( + coord->g11(), coord->g22(), coord->g33(), coord->g12(), 0.0, coord->g23())); // Now the normal test. output.write("Setting coefficients\n"); diff --git a/tests/integrated/test-multigrid_laplace/test_multigrid_laplace.cxx b/tests/integrated/test-multigrid_laplace/test_multigrid_laplace.cxx index 2b03f78049..55d93c746e 100644 --- a/tests/integrated/test-multigrid_laplace/test_multigrid_laplace.cxx +++ b/tests/integrated/test-multigrid_laplace/test_multigrid_laplace.cxx @@ -298,9 +298,9 @@ int main(int argc, char** argv) { Field3D this_Grad_perp_dot_Grad_perp(const Field3D& f, const Field3D& g) { auto* mesh = f.getMesh(); - Field3D result = mesh->getCoordinates()->g11 * ::DDX(f) * ::DDX(g) - + mesh->getCoordinates()->g33 * ::DDZ(f) * ::DDZ(g) - + mesh->getCoordinates()->g13 * (DDX(f) * DDZ(g) + DDZ(f) * DDX(g)); + Field3D result = mesh->getCoordinates()->g11() * ::DDX(f) * ::DDX(g) + + mesh->getCoordinates()->g33() * ::DDZ(f) * ::DDZ(g) + + mesh->getCoordinates()->g13() * (DDX(f) * DDZ(g) + DDZ(f) * DDX(g)); return result; } diff --git a/tests/integrated/test-naulin-laplace/test_naulin_laplace.cxx b/tests/integrated/test-naulin-laplace/test_naulin_laplace.cxx index 07a403e2e2..def323adf0 100644 --- a/tests/integrated/test-naulin-laplace/test_naulin_laplace.cxx +++ b/tests/integrated/test-naulin-laplace/test_naulin_laplace.cxx @@ -304,8 +304,9 @@ int main(int argc, char** argv) { Field3D this_Grad_perp_dot_Grad_perp(const Field3D& f, const Field3D& g) { const auto* coords = f.getCoordinates(); - Field3D result = coords->g11 * ::DDX(f) * ::DDX(g) + coords->g33 * ::DDZ(f) * ::DDZ(g) - + coords->g13 * (DDX(f) * DDZ(g) + DDZ(f) * DDX(g)); + Field3D result = coords->g11() * ::DDX(f) * ::DDX(g) + + coords->g33() * ::DDZ(f) * ::DDZ(g) + + coords->g13() * (DDX(f) * DDZ(g) + DDZ(f) * DDX(g)); return result; } diff --git a/tests/integrated/test-snb/test_snb.cxx b/tests/integrated/test-snb/test_snb.cxx index 1b96bfc8b1..96b053a183 100644 --- a/tests/integrated/test-snb/test_snb.cxx +++ b/tests/integrated/test-snb/test_snb.cxx @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include #include #include @@ -96,8 +98,8 @@ int main(int argc, char** argv) { Field3D Div_q = snb.divHeatFlux(Te, Ne, &Div_q_SH); // Check that flux is not zero - EXPECT_FALSE(IsFieldEqual(Div_q_SH, 0.0, "RGN_NOBNDRY")); - EXPECT_FALSE(IsFieldEqual(Div_q, 0.0, "RGN_NOBNDRY")); + EXPECT_FALSE(IsFieldEqual(Div_q_SH, 0.0, "RGN_NOBNDRY")) + EXPECT_FALSE(IsFieldEqual(Div_q, 0.0, "RGN_NOBNDRY")) } /////////////////////////////////////////////////////////// @@ -116,8 +118,8 @@ int main(int argc, char** argv) { Field3D Div_q = snb.divHeatFlux(Te, Ne, &Div_q_SH); // Check that flux is zero - EXPECT_TRUE(IsFieldEqual(Div_q_SH, 0.0, "RGN_NOBNDRY")); - EXPECT_TRUE(IsFieldEqual(Div_q, 0.0, "RGN_NOBNDRY")); + EXPECT_TRUE(IsFieldEqual(Div_q_SH, 0.0, "RGN_NOBNDRY")) + EXPECT_TRUE(IsFieldEqual(Div_q, 0.0, "RGN_NOBNDRY")) } /////////////////////////////////////////////////////////// @@ -135,7 +137,7 @@ int main(int argc, char** argv) { Field3D Div_q = snb.divHeatFlux(Te, Ne, &Div_q_SH); // Check that flux is zero - EXPECT_TRUE(IsFieldClose(Div_q, Div_q_SH, "RGN_NOBNDRY")); + EXPECT_TRUE(IsFieldClose(Div_q, Div_q_SH, "RGN_NOBNDRY")) } /////////////////////////////////////////////////////////// @@ -153,7 +155,7 @@ int main(int argc, char** argv) { Field3D Div_q = snb.divHeatFlux(Te, Ne, &Div_q_SH); // Check that fluxes are not equal - EXPECT_FALSE(IsFieldClose(Div_q, Div_q_SH, "RGN_NOBNDRY")); + EXPECT_FALSE(IsFieldClose(Div_q, Div_q_SH, "RGN_NOBNDRY")) } /////////////////////////////////////////////////////////// @@ -207,13 +209,19 @@ int main(int argc, char** argv) { // Change the mesh spacing and cell volume (Jdy) Coordinates* coord = Te.getCoordinates(); - for (int x = mesh->xstart; x <= mesh->xend; x++) { - for (int y = mesh->ystart; y <= mesh->yend; y++) { - double yn = (double(y) + 0.5) / double(mesh->yend + 1); + { + auto dy = emptyFrom(coord->dx()); + auto J = emptyFrom(coord->J()); + for (int x = mesh->xstart; x <= mesh->xend; x++) { + for (int y = mesh->ystart; y <= mesh->yend; y++) { + const double y_n = (double(y) + 0.5) / double(mesh->yend + 1); - coord->dy(x, y) = 1. - 0.9 * yn; - coord->J(x, y) = (1. + yn * yn); + dy(x, y) = 1. - 0.9 * y_n; + J(x, y) = 1. + y_n * y_n; + } } + coord->setDy(dy); + coord->setJ(J); } HeatFluxSNB snb; @@ -226,10 +234,10 @@ int main(int argc, char** argv) { Div_q *= SI::qe; // Check that fluxes are not equal - EXPECT_FALSE(IsFieldClose(Div_q, Div_q_SH, "RGN_NOBNDRY")); + EXPECT_FALSE(IsFieldClose(Div_q, Div_q_SH, "RGN_NOBNDRY")) - const Field2D dy = coord->dy; - const Field2D J = coord->J; + const Field2D dy = coord->dy(); + const Field2D J = coord->J(); // Integrate Div(q) over domain BoutReal q_sh = 0.0; @@ -242,7 +250,7 @@ int main(int argc, char** argv) { q_maxabs = BOUTMAX(q_maxabs, fabs(q_sh), fabs(q_snb)); } // Expect integrals to be the same - EXPECT_LT(fabs(q_sh - q_snb), 1e-8 * q_maxabs); + EXPECT_LT(fabs(q_sh - q_snb), 1e-8 * q_maxabs) } bout::checkForUnusedOptions(); diff --git a/tests/unit/bout_test_main.cxx b/tests/unit/bout_test_main.cxx index 999b5b0dc3..9ccb0b3918 100644 --- a/tests/unit/bout_test_main.cxx +++ b/tests/unit/bout_test_main.cxx @@ -21,6 +21,7 @@ GTEST_API_ int main(int argc, char** argv) { printf("Running main() from bout_test_main.cxx\n"); testing::InitGoogleTest(&argc, argv); + GTEST_FLAG_SET(death_test_style, "threadsafe"); // Explicitly setup and teardown PETSc to avoid reentry problems // with certain MPI implementations (see #1916 for details) diff --git a/tests/unit/fake_parallel_mesh.hxx b/tests/unit/fake_parallel_mesh.hxx index 805dcb2a0a..74f22296c6 100644 --- a/tests/unit/fake_parallel_mesh.hxx +++ b/tests/unit/fake_parallel_mesh.hxx @@ -296,7 +296,6 @@ std::vector createFakeProcessors(int nx, int ny, int nz, int n Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}); - // No call to Coordinates::geometry() needed here static_cast(&meshes[j + i * nype])->setCoordinates(test_coords); test_coords->setParallelTransform( bout::utils::make_unique(*bout::globals::mesh)); diff --git a/tests/unit/field/test_field_factory.cxx b/tests/unit/field/test_field_factory.cxx index ca51b845b3..c8688e46a6 100644 --- a/tests/unit/field/test_field_factory.cxx +++ b/tests/unit/field/test_field_factory.cxx @@ -560,7 +560,6 @@ TYPED_TEST(FieldFactoryCreationTest, CreateOnMesh) { Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0})); - // No call to Coordinates::geometry() needed here localmesh.getCoordinates()->setParallelTransform( bout::utils::make_unique(localmesh)); diff --git a/tests/unit/field/test_vector2d.cxx b/tests/unit/field/test_vector2d.cxx index 838876c02b..a21d8a3999 100644 --- a/tests/unit/field/test_vector2d.cxx +++ b/tests/unit/field/test_vector2d.cxx @@ -52,7 +52,6 @@ class Vector2DTest : public ::testing::Test { Field2D{1.0}, Field2D{2.0}, Field2D{3.0}, Field2D{4.0}, Field2D{5.0}, Field2D{6.0}, Field2D{1.0}, Field2D{2.0}, Field2D{3.0}, Field2D{4.0}, Field2D{5.0}, Field2D{6.0}, Field2D{0.0}, Field2D{0.0})); - // No call to Coordinates::geometry() needed here delete mesh_staggered; mesh_staggered = new FakeMesh(nx, ny, nz); diff --git a/tests/unit/field/test_vector3d.cxx b/tests/unit/field/test_vector3d.cxx index ece1f95fcc..20cca4b362 100644 --- a/tests/unit/field/test_vector3d.cxx +++ b/tests/unit/field/test_vector3d.cxx @@ -49,7 +49,6 @@ class Vector3DTest : public ::testing::Test { Field2D{1.0}, Field2D{2.0}, Field2D{3.0}, Field2D{4.0}, Field2D{5.0}, Field2D{6.0}, Field2D{1.0}, Field2D{2.0}, Field2D{3.0}, Field2D{4.0}, Field2D{5.0}, Field2D{6.0}, Field2D{0.0}, Field2D{0.0})); - // No call to Coordinates::geometry() needed here delete mesh_staggered; mesh_staggered = new FakeMesh(nx, ny, nz); diff --git a/tests/unit/include/bout/test_petsc_indexer.cxx b/tests/unit/include/bout/test_petsc_indexer.cxx index 3c20de9989..b10d8c8d62 100644 --- a/tests/unit/include/bout/test_petsc_indexer.cxx +++ b/tests/unit/include/bout/test_petsc_indexer.cxx @@ -51,7 +51,6 @@ class IndexerTest : public FakeMeshFixture { Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}); - // No call to Coordinates::geometry() needed here mesh2.setCoordinates(test_coords); // May need a ParallelTransform to create fields, because create3D calls // fromFieldAligned diff --git a/tests/unit/invert/laplace/test_laplace_cyclic.cxx b/tests/unit/invert/laplace/test_laplace_cyclic.cxx index 252c1f21c9..bb12021021 100644 --- a/tests/unit/invert/laplace/test_laplace_cyclic.cxx +++ b/tests/unit/invert/laplace/test_laplace_cyclic.cxx @@ -40,8 +40,8 @@ class CyclicForwardOperator { const Field3D operator()(Field3D& f) { auto result = d * Delp2(f) - + (coords->g11 * DDX(f) + coords->g13 * DDZ(f)) * DDX(c2) / c1 + a * f - + ex * DDX(f) + ez * DDZ(f); + + (coords->g11() * DDX(f) + coords->g13() * DDZ(f)) * DDX(c2) / c1 + + a * f + ex * DDX(f) + ez * DDZ(f); applyBoundaries(result, f); return result; } @@ -53,7 +53,7 @@ class CyclicForwardOperator { void applyBoundaries(Field3D& newF, const Field3D& f) { BOUT_FOR(i, f.getMesh()->getRegion3D("RGN_INNER_X")) { if (inner_x_neumann) { - newF[i] = (f[i.xp()] - f[i]) / coords->dx[i] / sqrt(coords->g_11[i]); + newF[i] = (f[i.xp()] - f[i]) / coords->dx()[i] / sqrt(coords->g_11()[i]); } else { newF[i] = 0.5 * (f[i] + f[i.xp()]); } @@ -61,7 +61,7 @@ class CyclicForwardOperator { BOUT_FOR(i, f.getMesh()->getRegion3D("RGN_OUTER_X")) { if (outer_x_neumann) { - newF[i] = (f[i] - f[i.xm()]) / coords->dx[i] / sqrt(coords->g_11[i]); + newF[i] = (f[i] - f[i.xm()]) / coords->dx()[i] / sqrt(coords->g_11()[i]); } else { newF[i] = 0.5 * (f[i.xm()] + f[i]); } @@ -85,7 +85,6 @@ class CyclicTest : public FakeMeshFixture, static_cast(bout::globals::mesh) ->setGridDataSource(new GridFromOptions(Options::getRoot())); - bout::globals::mesh->getCoordinates()->geometry(); f3.allocate(); coef2.allocate(); coef3.allocate(); diff --git a/tests/unit/invert/laplace/test_laplace_hypre3d.cxx b/tests/unit/invert/laplace/test_laplace_hypre3d.cxx index 1a11e98506..3a8bb811bd 100644 --- a/tests/unit/invert/laplace/test_laplace_hypre3d.cxx +++ b/tests/unit/invert/laplace/test_laplace_hypre3d.cxx @@ -45,7 +45,7 @@ class ForwardOperator { const Field3D operator()(Field3D& f) { auto result = d * Laplace_perp(f, CELL_DEFAULT, "free", "RGN_NOY") - + (Grad(f) * Grad(c2) - DDY(c2) * DDY(f) / coords->g_22) / c1 + a * f + + (Grad(f) * Grad(c2) - DDY(c2) * DDY(f) / coords->g_22()) / c1 + a * f + ex * DDX(f) + ez * DDZ(f); applyBoundaries(result, f); return result; @@ -61,7 +61,7 @@ class ForwardOperator { void applyBoundaries(Field3D& newF, Field3D& f) { BOUT_FOR(i, f.getMesh()->getRegion3D("RGN_INNER_X")) { if (inner_x_neumann) { - newF[i] = (f[i.xp()] - f[i]) / coords->dx[i] / sqrt(coords->g_11[i]); + newF[i] = (f[i.xp()] - f[i]) / coords->dx()[i] / sqrt(coords->g_11()[i]); } else { newF[i] = 0.5 * (f[i] + f[i.xp()]); } @@ -69,7 +69,7 @@ class ForwardOperator { BOUT_FOR(i, f.getMesh()->getRegion3D("RGN_OUTER_X")) { if (outer_x_neumann) { - newF[i] = (f[i] - f[i.xm()]) / coords->dx[i] / sqrt(coords->g_11[i]); + newF[i] = (f[i] - f[i.xm()]) / coords->dx()[i] / sqrt(coords->g_11()[i]); } else { newF[i] = 0.5 * (f[i.xm()] + f[i]); } @@ -77,7 +77,7 @@ class ForwardOperator { BOUT_FOR(i, f.getMesh()->getRegion3D("RGN_LOWER_Y")) { if (lower_y_neumann) { - newF[i] = (f[i.yp()] - f[i]) / coords->dx[i] / sqrt(coords->g_11[i]); + newF[i] = (f[i.yp()] - f[i]) / coords->dx()[i] / sqrt(coords->g_11()[i]); } else { newF[i] = 0.5 * (f[i] + f[i.yp()]); } @@ -85,7 +85,7 @@ class ForwardOperator { BOUT_FOR(i, f.getMesh()->getRegion3D("RGN_UPPER_Y")) { if (upper_y_neumann) { - newF[i] = (f[i] - f[i.ym()]) / coords->dx[i] / sqrt(coords->g_11[i]); + newF[i] = (f[i] - f[i.ym()]) / coords->dx()[i] / sqrt(coords->g_11()[i]); } else { newF[i] = 0.5 * (f[i.ym()] + f[i]); } @@ -103,7 +103,6 @@ class LaplaceHypre3dTest int nx = mesh->GlobalNx, ny = mesh->GlobalNy, nz = mesh->GlobalNz; static_cast(bout::globals::mesh) ->setGridDataSource(new GridFromOptions(Options::getRoot())); - bout::globals::mesh->getCoordinates()->geometry(); f3.allocate(); coef2.allocate(); coef3.allocate(); diff --git a/tests/unit/invert/laplace/test_laplace_petsc3damg.cxx b/tests/unit/invert/laplace/test_laplace_petsc3damg.cxx index b2831808a4..18d08800d2 100644 --- a/tests/unit/invert/laplace/test_laplace_petsc3damg.cxx +++ b/tests/unit/invert/laplace/test_laplace_petsc3damg.cxx @@ -45,7 +45,7 @@ class ForwardOperator { const Field3D operator()(Field3D& f) { auto result = d * Laplace_perp(f, CELL_DEFAULT, "free", "RGN_NOY") - + (Grad(f) * Grad(c2) - DDY(c2) * DDY(f) / coords->g_22) / c1 + a * f + + (Grad(f) * Grad(c2) - DDY(c2) * DDY(f) / coords->g_22()) / c1 + a * f + ex * DDX(f) + ez * DDZ(f); applyBoundaries(result, f); return result; @@ -61,7 +61,7 @@ class ForwardOperator { void applyBoundaries(Field3D& newF, Field3D& f) { BOUT_FOR(i, f.getMesh()->getRegion3D("RGN_INNER_X")) { if (inner_x_neumann) { - newF[i] = (f[i.xp()] - f[i]) / coords->dx[i] / sqrt(coords->g_11[i]); + newF[i] = (f[i.xp()] - f[i]) / coords->dx()[i] / sqrt(coords->g_11()[i]); } else { newF[i] = 0.5 * (f[i] + f[i.xp()]); } @@ -69,7 +69,7 @@ class ForwardOperator { BOUT_FOR(i, f.getMesh()->getRegion3D("RGN_OUTER_X")) { if (outer_x_neumann) { - newF[i] = (f[i] - f[i.xm()]) / coords->dx[i] / sqrt(coords->g_11[i]); + newF[i] = (f[i] - f[i.xm()]) / coords->dx()[i] / sqrt(coords->g_11()[i]); } else { newF[i] = 0.5 * (f[i.xm()] + f[i]); } @@ -77,7 +77,7 @@ class ForwardOperator { BOUT_FOR(i, f.getMesh()->getRegion3D("RGN_LOWER_Y")) { if (lower_y_neumann) { - newF[i] = (f[i.yp()] - f[i]) / coords->dx[i] / sqrt(coords->g_11[i]); + newF[i] = (f[i.yp()] - f[i]) / coords->dx()[i] / sqrt(coords->g_11()[i]); } else { newF[i] = 0.5 * (f[i] + f[i.yp()]); } @@ -85,7 +85,7 @@ class ForwardOperator { BOUT_FOR(i, f.getMesh()->getRegion3D("RGN_UPPER_Y")) { if (upper_y_neumann) { - newF[i] = (f[i] - f[i.ym()]) / coords->dx[i] / sqrt(coords->g_11[i]); + newF[i] = (f[i] - f[i.ym()]) / coords->dx()[i] / sqrt(coords->g_11()[i]); } else { newF[i] = 0.5 * (f[i.ym()] + f[i]); } @@ -104,7 +104,6 @@ class Petsc3dAmgTest int nx = mesh->GlobalNx, ny = mesh->GlobalNy, nz = mesh->GlobalNz; static_cast(bout::globals::mesh) ->setGridDataSource(new GridFromOptions(Options::getRoot())); - bout::globals::mesh->getCoordinates()->geometry(); f3.allocate(); coef2.allocate(); coef3.allocate(); diff --git a/tests/unit/mesh/data/test_gridfromoptions.cxx b/tests/unit/mesh/data/test_gridfromoptions.cxx index 84f08ff47b..ef6441768d 100644 --- a/tests/unit/mesh/data/test_gridfromoptions.cxx +++ b/tests/unit/mesh/data/test_gridfromoptions.cxx @@ -359,12 +359,12 @@ TEST_F(GridFromOptionsTest, CoordinatesCentre) { mesh_from_options.communicate(expected_2d); - EXPECT_TRUE(IsFieldEqual(coords->g11, expected_metric + 5.)); - EXPECT_TRUE(IsFieldEqual(coords->g22, expected_metric + 4.)); - EXPECT_TRUE(IsFieldEqual(coords->g33, expected_metric + 3.)); - EXPECT_TRUE(IsFieldEqual(coords->g12, expected_metric + 2.)); - EXPECT_TRUE(IsFieldEqual(coords->g13, expected_metric + 1.)); - EXPECT_TRUE(IsFieldEqual(coords->g23, expected_metric)); + EXPECT_TRUE(IsFieldEqual(coords->g11(), expected_metric + 5.)); + EXPECT_TRUE(IsFieldEqual(coords->g22(), expected_metric + 4.)); + EXPECT_TRUE(IsFieldEqual(coords->g33(), expected_metric + 3.)); + EXPECT_TRUE(IsFieldEqual(coords->g12(), expected_metric + 2.)); + EXPECT_TRUE(IsFieldEqual(coords->g13(), expected_metric + 1.)); + EXPECT_TRUE(IsFieldEqual(coords->g23(), expected_metric)); } #if not(BOUT_USE_METRIC_3D) @@ -373,12 +373,12 @@ TEST_F(GridFromOptionsTest, CoordinatesZlow) { mesh_from_options.communicate(expected_2d); - EXPECT_TRUE(IsFieldEqual(coords->g11, expected_metric + 5.)); - EXPECT_TRUE(IsFieldEqual(coords->g22, expected_metric + 4.)); - EXPECT_TRUE(IsFieldEqual(coords->g33, expected_metric + 3.)); - EXPECT_TRUE(IsFieldEqual(coords->g12, expected_metric + 2.)); - EXPECT_TRUE(IsFieldEqual(coords->g13, expected_metric + 1.)); - EXPECT_TRUE(IsFieldEqual(coords->g23, expected_metric)); + EXPECT_TRUE(IsFieldEqual(coords->g11(), expected_metric + 5.)); + EXPECT_TRUE(IsFieldEqual(coords->g22(), expected_metric + 4.)); + EXPECT_TRUE(IsFieldEqual(coords->g33(), expected_metric + 3.)); + EXPECT_TRUE(IsFieldEqual(coords->g12(), expected_metric + 2.)); + EXPECT_TRUE(IsFieldEqual(coords->g13(), expected_metric + 1.)); + EXPECT_TRUE(IsFieldEqual(coords->g23(), expected_metric)); } #else // Maybe replace by MMS test, because we need a periodic function in z. @@ -393,7 +393,7 @@ TEST_F(GridFromOptionsTest, CoordinatesXlowInterp) { auto coords = mesh_from_options.getCoordinates(CELL_XLOW); - Coordinates::FieldMetric expected_xlow = makeField( + auto expected_xlow = makeField( [](Coordinates::FieldMetric::ind_type& index) { return index.x() - 0.5 + (TWOPI * index.y()) + (TWOPI * index.z() / nz) + 3; }, @@ -402,16 +402,16 @@ TEST_F(GridFromOptionsTest, CoordinatesXlowInterp) { mesh_from_options.communicate(expected_xlow); EXPECT_TRUE( - IsFieldEqual(coords->g11, expected_xlow + 5., "RGN_NOBNDRY", this_tolerance)); + IsFieldEqual(coords->g11(), expected_xlow + 5., "RGN_NOBNDRY", this_tolerance)); EXPECT_TRUE( - IsFieldEqual(coords->g22, expected_xlow + 4., "RGN_NOBNDRY", this_tolerance)); + IsFieldEqual(coords->g22(), expected_xlow + 4., "RGN_NOBNDRY", this_tolerance)); EXPECT_TRUE( - IsFieldEqual(coords->g33, expected_xlow + 3., "RGN_NOBNDRY", this_tolerance)); + IsFieldEqual(coords->g33(), expected_xlow + 3., "RGN_NOBNDRY", this_tolerance)); EXPECT_TRUE( - IsFieldEqual(coords->g12, expected_xlow + 2., "RGN_NOBNDRY", this_tolerance)); + IsFieldEqual(coords->g12(), expected_xlow + 2., "RGN_NOBNDRY", this_tolerance)); EXPECT_TRUE( - IsFieldEqual(coords->g13, expected_xlow + 1., "RGN_NOBNDRY", this_tolerance)); - EXPECT_TRUE(IsFieldEqual(coords->g23, expected_xlow, "RGN_NOBNDRY", this_tolerance)); + IsFieldEqual(coords->g13(), expected_xlow + 1., "RGN_NOBNDRY", this_tolerance)); + EXPECT_TRUE(IsFieldEqual(coords->g23(), expected_xlow, "RGN_NOBNDRY", this_tolerance)); } TEST_F(GridFromOptionsTest, CoordinatesXlowRead) { @@ -434,7 +434,7 @@ TEST_F(GridFromOptionsTest, CoordinatesXlowRead) { auto coords = mesh_from_options.getCoordinates(CELL_XLOW); - Field2D expected_xlow = makeField( + auto expected_xlow = makeField( [](Field2D::ind_type& index) { return (nx - index.x() + 0.5) + (TWOPI * index.y()) + (TWOPI * index.z() / nz) + 3; @@ -443,18 +443,18 @@ TEST_F(GridFromOptionsTest, CoordinatesXlowRead) { mesh_from_options.communicate(expected_xlow); - EXPECT_TRUE(IsFieldEqual(coords->g11, expected_xlow + 5.)); - EXPECT_TRUE(coords->g11.getLocation() == CELL_XLOW); - EXPECT_TRUE(IsFieldEqual(coords->g22, expected_xlow + 4.)); - EXPECT_TRUE(coords->g22.getLocation() == CELL_XLOW); - EXPECT_TRUE(IsFieldEqual(coords->g33, expected_xlow + 3.)); - EXPECT_TRUE(coords->g33.getLocation() == CELL_XLOW); - EXPECT_TRUE(IsFieldEqual(coords->g12, expected_xlow + 2.)); - EXPECT_TRUE(coords->g12.getLocation() == CELL_XLOW); - EXPECT_TRUE(IsFieldEqual(coords->g13, expected_xlow + 1.)); - EXPECT_TRUE(coords->g13.getLocation() == CELL_XLOW); - EXPECT_TRUE(IsFieldEqual(coords->g23, expected_xlow)); - EXPECT_TRUE(coords->g23.getLocation() == CELL_XLOW); + EXPECT_TRUE(IsFieldEqual(coords->g11(), expected_xlow + 5.)); + EXPECT_TRUE(coords->g11().getLocation() == CELL_XLOW); + EXPECT_TRUE(IsFieldEqual(coords->g22(), expected_xlow + 4.)); + EXPECT_TRUE(coords->g22().getLocation() == CELL_XLOW); + EXPECT_TRUE(IsFieldEqual(coords->g33(), expected_xlow + 3.)); + EXPECT_TRUE(coords->g33().getLocation() == CELL_XLOW); + EXPECT_TRUE(IsFieldEqual(coords->g12(), expected_xlow + 2.)); + EXPECT_TRUE(coords->g12().getLocation() == CELL_XLOW); + EXPECT_TRUE(IsFieldEqual(coords->g13(), expected_xlow + 1.)); + EXPECT_TRUE(coords->g13().getLocation() == CELL_XLOW); + EXPECT_TRUE(IsFieldEqual(coords->g23(), expected_xlow)); + EXPECT_TRUE(coords->g23().getLocation() == CELL_XLOW); } TEST_F(GridFromOptionsTest, CoordinatesYlowInterp) { @@ -467,7 +467,7 @@ TEST_F(GridFromOptionsTest, CoordinatesYlowInterp) { auto* coords = mesh_from_options.getCoordinates(CELL_YLOW); - Field2D expected_ylow = makeField( + auto expected_ylow = makeField( [](Field2D::ind_type& index) { return index.x() + (TWOPI * (index.y() - 0.5)) + (TWOPI * index.z() / nz) + 3; }, @@ -476,22 +476,22 @@ TEST_F(GridFromOptionsTest, CoordinatesYlowInterp) { mesh_from_options.communicate(expected_ylow); EXPECT_TRUE( - IsFieldEqual(coords->g11, expected_ylow + 5., "RGN_NOBNDRY", this_tolerance)); - EXPECT_TRUE(coords->g11.getLocation() == CELL_YLOW); + IsFieldEqual(coords->g11(), expected_ylow + 5., "RGN_NOBNDRY", this_tolerance)); + EXPECT_TRUE(coords->g11().getLocation() == CELL_YLOW); EXPECT_TRUE( - IsFieldEqual(coords->g22, expected_ylow + 4., "RGN_NOBNDRY", this_tolerance)); - EXPECT_TRUE(coords->g22.getLocation() == CELL_YLOW); + IsFieldEqual(coords->g22(), expected_ylow + 4., "RGN_NOBNDRY", this_tolerance)); + EXPECT_TRUE(coords->g22().getLocation() == CELL_YLOW); EXPECT_TRUE( - IsFieldEqual(coords->g33, expected_ylow + 3., "RGN_NOBNDRY", this_tolerance)); - EXPECT_TRUE(coords->g33.getLocation() == CELL_YLOW); + IsFieldEqual(coords->g33(), expected_ylow + 3., "RGN_NOBNDRY", this_tolerance)); + EXPECT_TRUE(coords->g33().getLocation() == CELL_YLOW); EXPECT_TRUE( - IsFieldEqual(coords->g12, expected_ylow + 2., "RGN_NOBNDRY", this_tolerance)); - EXPECT_TRUE(coords->g12.getLocation() == CELL_YLOW); + IsFieldEqual(coords->g12(), expected_ylow + 2., "RGN_NOBNDRY", this_tolerance)); + EXPECT_TRUE(coords->g12().getLocation() == CELL_YLOW); EXPECT_TRUE( - IsFieldEqual(coords->g13, expected_ylow + 1., "RGN_NOBNDRY", this_tolerance)); - EXPECT_TRUE(coords->g13.getLocation() == CELL_YLOW); - EXPECT_TRUE(IsFieldEqual(coords->g23, expected_ylow, "RGN_NOBNDRY", this_tolerance)); - EXPECT_TRUE(coords->g23.getLocation() == CELL_YLOW); + IsFieldEqual(coords->g13(), expected_ylow + 1., "RGN_NOBNDRY", this_tolerance)); + EXPECT_TRUE(coords->g13().getLocation() == CELL_YLOW); + EXPECT_TRUE(IsFieldEqual(coords->g23(), expected_ylow, "RGN_NOBNDRY", this_tolerance)); + EXPECT_TRUE(coords->g23().getLocation() == CELL_YLOW); #endif } @@ -517,7 +517,7 @@ TEST_F(GridFromOptionsTest, CoordinatesYlowRead) { auto coords = mesh_from_options.getCoordinates(CELL_YLOW); - Field2D expected_ylow = makeField( + auto expected_ylow = makeField( [](Field2D::ind_type& index) { return index.x() + (TWOPI * (ny - index.y() + 0.5)) + (TWOPI * index.z() / nz) + 3; @@ -526,18 +526,18 @@ TEST_F(GridFromOptionsTest, CoordinatesYlowRead) { mesh_from_options.communicate(expected_ylow); - EXPECT_TRUE(IsFieldEqual(coords->g11, expected_ylow + 5., "RGN_ALL", this_tolerance)); - EXPECT_TRUE(coords->g11.getLocation() == CELL_YLOW); - EXPECT_TRUE(IsFieldEqual(coords->g22, expected_ylow + 4., "RGN_ALL", this_tolerance)); - EXPECT_TRUE(coords->g22.getLocation() == CELL_YLOW); - EXPECT_TRUE(IsFieldEqual(coords->g33, expected_ylow + 3., "RGN_ALL", this_tolerance)); - EXPECT_TRUE(coords->g33.getLocation() == CELL_YLOW); - EXPECT_TRUE(IsFieldEqual(coords->g12, expected_ylow + 2., "RGN_ALL", this_tolerance)); - EXPECT_TRUE(coords->g12.getLocation() == CELL_YLOW); - EXPECT_TRUE(IsFieldEqual(coords->g13, expected_ylow + 1., "RGN_ALL", this_tolerance)); - EXPECT_TRUE(coords->g13.getLocation() == CELL_YLOW); - EXPECT_TRUE(IsFieldEqual(coords->g23, expected_ylow, "RGN_ALL", this_tolerance)); - EXPECT_TRUE(coords->g23.getLocation() == CELL_YLOW); + EXPECT_TRUE(IsFieldEqual(coords->g11(), expected_ylow + 5., "RGN_ALL", this_tolerance)); + EXPECT_TRUE(coords->g11().getLocation() == CELL_YLOW); + EXPECT_TRUE(IsFieldEqual(coords->g22(), expected_ylow + 4., "RGN_ALL", this_tolerance)); + EXPECT_TRUE(coords->g22().getLocation() == CELL_YLOW); + EXPECT_TRUE(IsFieldEqual(coords->g33(), expected_ylow + 3., "RGN_ALL", this_tolerance)); + EXPECT_TRUE(coords->g33().getLocation() == CELL_YLOW); + EXPECT_TRUE(IsFieldEqual(coords->g12(), expected_ylow + 2., "RGN_ALL", this_tolerance)); + EXPECT_TRUE(coords->g12().getLocation() == CELL_YLOW); + EXPECT_TRUE(IsFieldEqual(coords->g13(), expected_ylow + 1., "RGN_ALL", this_tolerance)); + EXPECT_TRUE(coords->g13().getLocation() == CELL_YLOW); + EXPECT_TRUE(IsFieldEqual(coords->g23(), expected_ylow, "RGN_ALL", this_tolerance)); + EXPECT_TRUE(coords->g23().getLocation() == CELL_YLOW); #endif } @@ -548,11 +548,11 @@ TEST_F(GridFromOptionsTest, CoordinatesZlowRead) { auto coords = mesh_from_options.getCoordinates(CELL_ZLOW); - EXPECT_TRUE(IsFieldEqual(coords->g11, expected_2d + 5.)); - EXPECT_TRUE(IsFieldEqual(coords->g22, expected_2d + 4.)); - EXPECT_TRUE(IsFieldEqual(coords->g33, expected_2d + 3.)); - EXPECT_TRUE(IsFieldEqual(coords->g12, expected_2d + 2.)); - EXPECT_TRUE(IsFieldEqual(coords->g13, expected_2d + 1.)); - EXPECT_TRUE(IsFieldEqual(coords->g23, expected_2d)); + EXPECT_TRUE(IsFieldEqual(coords->g11(), expected_2d + 5.)); + EXPECT_TRUE(IsFieldEqual(coords->g22(), expected_2d + 4.)); + EXPECT_TRUE(IsFieldEqual(coords->g33(), expected_2d + 3.)); + EXPECT_TRUE(IsFieldEqual(coords->g12(), expected_2d + 2.)); + EXPECT_TRUE(IsFieldEqual(coords->g13(), expected_2d + 1.)); + EXPECT_TRUE(IsFieldEqual(coords->g23(), expected_2d)); #endif } diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index fbeaa10c3a..bbf6664637 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -42,11 +42,10 @@ class ShiftedMetricTest : public ::testing::Test { Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0})); - // No call to Coordinates::geometry() needed here auto coords = mesh->getCoordinates(); coords->setParallelTransform(bout::utils::make_unique( - *mesh, CELL_CENTRE, zShift, coords->zlength()(0, 0))); + *mesh, CELL_CENTRE, zShift, coords->zlength(0, 0))); Field3D input_temp{mesh}; diff --git a/tests/unit/mesh/test_coordinates.cxx b/tests/unit/mesh/test_coordinates.cxx index f862e24321..2b3f8c7887 100644 --- a/tests/unit/mesh/test_coordinates.cxx +++ b/tests/unit/mesh/test_coordinates.cxx @@ -46,7 +46,6 @@ TEST_F(CoordinatesTest, ZLength) { FieldMetric{0.0}, // g_23 FieldMetric{0.0}, // ShiftTorsion FieldMetric{0.0}}; // IntShiftTorsion - // No call to Coordinates::geometry() needed here EXPECT_TRUE(IsFieldEqual(coords.zlength(), 7.0)); } @@ -79,7 +78,6 @@ TEST_F(CoordinatesTest, ZLength3D) { FieldMetric{0.0}, // g_23 FieldMetric{0.0}, // ShiftTorsion FieldMetric{0.0}}; // IntShiftTorsion - // No call to Coordinates::geometry() needed here EXPECT_TRUE(IsFieldEqual(coords.zlength(), expected)); } @@ -106,12 +104,11 @@ TEST_F(CoordinatesTest, Jacobian) { FieldMetric{0.0}, // g_23 FieldMetric{0.0}, // ShiftTorsion FieldMetric{0.0}}; // IntShiftTorsion - // No call to Coordinates::geometry() needed here - EXPECT_NO_THROW(coords.jacobian()); + EXPECT_NO_THROW(coords.recalculateJacobian()); - EXPECT_TRUE(IsFieldEqual(coords.J, 1.0)); - EXPECT_TRUE(IsFieldEqual(coords.Bxy, 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.J(), 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.Bxy(), 1.0)); } /// To do generalise these tests @@ -137,18 +134,16 @@ TEST_F(CoordinatesTest, CalcContravariant) { FieldMetric{0.0}, // g_23 FieldMetric{0.0}, // ShiftTorsion FieldMetric{0.0}}; // IntShiftTorsion - // No call to Coordinates::geometry() needed here - output_info.disable(); - coords.calcCovariant(); - output_info.enable(); + coords.setContravariantMetricTensor( + ContravariantMetricTensor(1.0, 1.0, 1.0, 0.0, 0.0, 0.0)); - EXPECT_TRUE(IsFieldEqual(coords.g_11, 1.0)); - EXPECT_TRUE(IsFieldEqual(coords.g_22, 1.0)); - EXPECT_TRUE(IsFieldEqual(coords.g_33, 1.0)); - EXPECT_TRUE(IsFieldEqual(coords.g_12, 0.0)); - EXPECT_TRUE(IsFieldEqual(coords.g_13, 0.0)); - EXPECT_TRUE(IsFieldEqual(coords.g_23, 0.0)); + EXPECT_TRUE(IsFieldEqual(coords.g_11(), 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.g_22(), 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.g_33(), 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.g_12(), 0.0)); + EXPECT_TRUE(IsFieldEqual(coords.g_13(), 0.0)); + EXPECT_TRUE(IsFieldEqual(coords.g_23(), 0.0)); } TEST_F(CoordinatesTest, CalcCovariant) { @@ -172,18 +167,15 @@ TEST_F(CoordinatesTest, CalcCovariant) { FieldMetric{0.0}, // g_23 FieldMetric{0.0}, // ShiftTorsion FieldMetric{0.0}}; // IntShiftTorsion - // No call to Coordinates::geometry() needed here - output_info.disable(); - coords.calcContravariant(); - output_info.enable(); + coords.setCovariantMetricTensor(CovariantMetricTensor(1.0, 1.0, 1.0, 0.0, 0.0, 0.0)); - EXPECT_TRUE(IsFieldEqual(coords.g11, 1.0)); - EXPECT_TRUE(IsFieldEqual(coords.g22, 1.0)); - EXPECT_TRUE(IsFieldEqual(coords.g33, 1.0)); - EXPECT_TRUE(IsFieldEqual(coords.g12, 0.0)); - EXPECT_TRUE(IsFieldEqual(coords.g13, 0.0)); - EXPECT_TRUE(IsFieldEqual(coords.g23, 0.0)); + EXPECT_TRUE(IsFieldEqual(coords.g11(), 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.g22(), 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.g33(), 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.g12(), 0.0)); + EXPECT_TRUE(IsFieldEqual(coords.g13(), 0.0)); + EXPECT_TRUE(IsFieldEqual(coords.g23(), 0.0)); } // #endif @@ -194,19 +186,19 @@ TEST_F(CoordinatesTest, DefaultConstructor) { output_warn.enable(); output_info.enable(); - EXPECT_TRUE(IsFieldEqual(coords.dx, 1.0)); - EXPECT_TRUE(IsFieldEqual(coords.dy, 1.0)); - EXPECT_TRUE(IsFieldEqual(coords.dz, default_dz)); + EXPECT_TRUE(IsFieldEqual(coords.dx(), 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.dy(), 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.dz(), default_dz)); - EXPECT_TRUE(IsFieldEqual(coords.g11, 1.0)); - EXPECT_TRUE(IsFieldEqual(coords.g22, 1.0)); - EXPECT_TRUE(IsFieldEqual(coords.g33, 1.0)); - EXPECT_TRUE(IsFieldEqual(coords.g12, 0.0)); - EXPECT_TRUE(IsFieldEqual(coords.g13, 0.0)); - EXPECT_TRUE(IsFieldEqual(coords.g23, 0.0)); + EXPECT_TRUE(IsFieldEqual(coords.g11(), 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.g22(), 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.g33(), 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.g12(), 0.0)); + EXPECT_TRUE(IsFieldEqual(coords.g13(), 0.0)); + EXPECT_TRUE(IsFieldEqual(coords.g23(), 0.0)); - EXPECT_TRUE(IsFieldEqual(coords.J, 1.0)); - EXPECT_TRUE(IsFieldEqual(coords.Bxy, 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.J(), 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.Bxy(), 1.0)); } TEST_F(CoordinatesTest, ConstructWithMeshSpacing) { @@ -220,31 +212,28 @@ TEST_F(CoordinatesTest, ConstructWithMeshSpacing) { output_warn.enable(); output_info.enable(); - EXPECT_TRUE(IsFieldEqual(coords.dx, 2.0)); - EXPECT_TRUE(IsFieldEqual(coords.dy, 3.2)); - EXPECT_TRUE(IsFieldEqual(coords.dz, 42.)); + EXPECT_TRUE(IsFieldEqual(coords.dx(), 2.0)); + EXPECT_TRUE(IsFieldEqual(coords.dy(), 3.2)); + EXPECT_TRUE(IsFieldEqual(coords.dz(), 42.)); - EXPECT_TRUE(IsFieldEqual(coords.g11, 1.0)); - EXPECT_TRUE(IsFieldEqual(coords.g22, 1.0)); - EXPECT_TRUE(IsFieldEqual(coords.g33, 1.0)); - EXPECT_TRUE(IsFieldEqual(coords.g12, 0.0)); - EXPECT_TRUE(IsFieldEqual(coords.g13, 0.0)); - EXPECT_TRUE(IsFieldEqual(coords.g23, 0.0)); + EXPECT_TRUE(IsFieldEqual(coords.g11(), 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.g22(), 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.g33(), 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.g12(), 0.0)); + EXPECT_TRUE(IsFieldEqual(coords.g13(), 0.0)); + EXPECT_TRUE(IsFieldEqual(coords.g23(), 0.0)); - EXPECT_TRUE(IsFieldEqual(coords.J, 1.0)); - EXPECT_TRUE(IsFieldEqual(coords.Bxy, 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.J(), 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.Bxy(), 1.0)); } TEST_F(CoordinatesTest, SmallMeshSpacing) { static_cast(bout::globals::mesh) ->setGridDataSource(new FakeGridDataSource({{"dx", 1e-9}})); - output_info.disable(); - output_warn.disable(); - Coordinates coords(mesh); - EXPECT_THROW(coords.geometry(), BoutException); - output_warn.enable(); - output_info.enable(); + WithQuietOutput quiet_info{output_info}; + WithQuietOutput quiet_warn{output_warn}; + EXPECT_THROW(Coordinates{mesh}, BoutException); } TEST_F(CoordinatesTest, ConstructWithDiagonalContravariantMetric) { @@ -260,26 +249,26 @@ TEST_F(CoordinatesTest, ConstructWithDiagonalContravariantMetric) { output_info.enable(); // Didn't specify grid spacing, so default to 1 - EXPECT_TRUE(IsFieldEqual(coords.dx, 1.0)); - EXPECT_TRUE(IsFieldEqual(coords.dy, 1.0)); - EXPECT_TRUE(IsFieldEqual(coords.dz, default_dz)); + EXPECT_TRUE(IsFieldEqual(coords.dx(), 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.dy(), 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.dz(), default_dz)); // Diagonal contravariant metric - EXPECT_TRUE(IsFieldEqual(coords.g11, 2.0)); - EXPECT_TRUE(IsFieldEqual(coords.g22, 3.2)); - EXPECT_TRUE(IsFieldEqual(coords.g33, 42)); - EXPECT_TRUE(IsFieldEqual(coords.g12, 0.0)); - EXPECT_TRUE(IsFieldEqual(coords.g13, 0.0)); - EXPECT_TRUE(IsFieldEqual(coords.g23, 0.0)); + EXPECT_TRUE(IsFieldEqual(coords.g11(), 2.0)); + EXPECT_TRUE(IsFieldEqual(coords.g22(), 3.2)); + EXPECT_TRUE(IsFieldEqual(coords.g33(), 42)); + EXPECT_TRUE(IsFieldEqual(coords.g12(), 0.0)); + EXPECT_TRUE(IsFieldEqual(coords.g13(), 0.0)); + EXPECT_TRUE(IsFieldEqual(coords.g23(), 0.0)); // Covariant metric should be inverse // Note: Not calculated in corners - EXPECT_TRUE(IsFieldEqual(coords.g_11, 1. / 2.0, "RGN_NOCORNERS")); - EXPECT_TRUE(IsFieldEqual(coords.g_22, 1. / 3.2, "RGN_NOCORNERS")); - EXPECT_TRUE(IsFieldEqual(coords.g_33, 1. / 42, "RGN_NOCORNERS")); + EXPECT_TRUE(IsFieldEqual(coords.g_11(), 1. / 2.0, "RGN_NOCORNERS")); + EXPECT_TRUE(IsFieldEqual(coords.g_22(), 1. / 3.2, "RGN_NOCORNERS")); + EXPECT_TRUE(IsFieldEqual(coords.g_33(), 1. / 42, "RGN_NOCORNERS")); - EXPECT_TRUE(IsFieldEqual(coords.J, 1. / sqrt(2.0 * 3.2 * 42), "RGN_NOCORNERS")); - EXPECT_TRUE(IsFieldEqual(coords.Bxy, sqrt(2.0 * 42), "RGN_NOCORNERS", 1e-10)); + EXPECT_TRUE(IsFieldEqual(coords.J(), 1. / sqrt(2.0 * 3.2 * 42), "RGN_NOCORNERS")); + EXPECT_TRUE(IsFieldEqual(coords.Bxy(), sqrt(2.0 * 42), "RGN_NOCORNERS", 1e-10)); } TEST_F(CoordinatesTest, NegativeJacobian) { @@ -303,3 +292,282 @@ TEST_F(CoordinatesTest, NegativeB) { output_warn.enable(); output_info.enable(); } + +TEST_F(CoordinatesTest, GetContravariantMetricTensor) { + Coordinates coords{mesh, + FieldMetric{1.0}, // dx + FieldMetric{1.0}, // dy + FieldMetric{1.0}, // dz + FieldMetric{0.0}, // J + FieldMetric{0.0}, // Bxy + FieldMetric{1.2}, // g11 + FieldMetric{2.3}, // g22 + FieldMetric{3.4}, // g33 + FieldMetric{4.5}, // g12 + FieldMetric{5.6}, // g13 + FieldMetric{6.7}, // g23 + FieldMetric{1.0}, // g_11 + FieldMetric{1.0}, // g_22 + FieldMetric{1.0}, // g_23 + FieldMetric{0.0}, // g_12 + FieldMetric{0.0}, // g_13 + FieldMetric{0.0}, // g_23 + FieldMetric{0.0}, // ShiftTorsion + FieldMetric{0.0}}; // IntShiftTorsion + + EXPECT_TRUE(IsFieldEqual(coords.g11(), 1.2)); + EXPECT_TRUE(IsFieldEqual(coords.g22(), 2.3)); + EXPECT_TRUE(IsFieldEqual(coords.g33(), 3.4)); + EXPECT_TRUE(IsFieldEqual(coords.g12(), 4.5)); + EXPECT_TRUE(IsFieldEqual(coords.g13(), 5.6)); + EXPECT_TRUE(IsFieldEqual(coords.g23(), 6.7)); +} + +TEST_F(CoordinatesTest, SetContravariantMetricTensor) { + // Set initial values for the metric tensor in the Coordinates constructor + Coordinates coords{mesh, + FieldMetric{1.0}, // dx + FieldMetric{1.0}, // dy + FieldMetric{1.0}, // dz + FieldMetric{0.0}, // J + FieldMetric{0.0}, // Bxy + FieldMetric{0.0}, // g11 + FieldMetric{0.0}, // g22 + FieldMetric{0.0}, // g33 + FieldMetric{0.0}, // g12 + FieldMetric{0.0}, // g13 + FieldMetric{0.0}, // g23 + FieldMetric{1.0}, // g_11 + FieldMetric{1.0}, // g_22 + FieldMetric{1.0}, // g_23 + FieldMetric{0.0}, // g_12 + FieldMetric{0.0}, // g_13 + FieldMetric{0.0}, // g_23 + FieldMetric{0.0}, // ShiftTorsion + FieldMetric{0.0}}; // IntShiftTorsion + + // Modify with setter + auto updated_metric_tensor = ContravariantMetricTensor(1.0, 2.0, 0.4, 1.0, 0.0, 0.2); + coords.setContravariantMetricTensor(updated_metric_tensor); + + // Get values with getter and check they have been modified as expected + EXPECT_TRUE(IsFieldEqual(coords.g11(), 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.g22(), 2.0)); + EXPECT_TRUE(IsFieldEqual(coords.g33(), 0.4)); + EXPECT_TRUE(IsFieldEqual(coords.g12(), 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.g13(), 0.0)); + EXPECT_TRUE(IsFieldEqual(coords.g23(), 0.2)); +} + +TEST_F(CoordinatesTest, CheckCovariantCalculatedFromContravariant) { + + // Set initial values for the metric tensor in the Coordinates constructor + Coordinates coords{mesh, + FieldMetric{1.0}, // dx + FieldMetric{1.0}, // dy + FieldMetric{1.0}, // dz + FieldMetric{0.0}, // J + FieldMetric{0.0}, // Bxy + FieldMetric{0.0}, // g11 + FieldMetric{0.0}, // g22 + FieldMetric{0.0}, // g33 + FieldMetric{0.0}, // g12 + FieldMetric{0.0}, // g13 + FieldMetric{0.0}, // g23 + FieldMetric{1.0}, // g_11 + FieldMetric{1.0}, // g_22 + FieldMetric{1.0}, // g_23 + FieldMetric{0.0}, // g_12 + FieldMetric{0.0}, // g_13 + FieldMetric{0.0}, // g_23 + FieldMetric{0.0}, // ShiftTorsion + FieldMetric{0.0}}; // IntShiftTorsion + + // Modify contravariant components + constexpr double g11 = 1.0; + constexpr double g22 = 1.0; + constexpr double g33 = 1.0; + const double g12 = sqrt(3.0) / 4.0; // (std::sqrt only constexpr since C++26) + constexpr double g13 = 0.5; + const double g23 = sqrt(3.0) / 4.0; // (std::sqrt only constexpr since C++26) + auto updated_metric_tensor = ContravariantMetricTensor(g11, g22, g33, g12, g13, g23); + coords.setContravariantMetricTensor(updated_metric_tensor); + + // Check that the covariant components have been calculated corrected + constexpr double expected_g_11 = 13.0 / 9.0; + constexpr double expected_g_22 = 4.0 / 3.0; + constexpr double expected_g_33 = 13.0 / 9.0; + const double expected_g_12 = -2.0 * sqrt(3.0) / 9.0; + constexpr double expected_g_13 = -5.0 / 9.0; + const double expected_g_23 = -2.0 * sqrt(3.0) / 9.0; + + EXPECT_TRUE(IsFieldEqual(coords.g_11(), expected_g_11)); + EXPECT_TRUE(IsFieldEqual(coords.g_22(), expected_g_22)); + EXPECT_TRUE(IsFieldEqual(coords.g_33(), expected_g_33)); + EXPECT_TRUE(IsFieldEqual(coords.g_12(), expected_g_12)); + EXPECT_TRUE(IsFieldEqual(coords.g_13(), expected_g_13)); + EXPECT_TRUE(IsFieldEqual(coords.g_23(), expected_g_23)); +} + +TEST_F(CoordinatesTest, CheckContravariantCalculatedFromCovariant) { + + // Set initial values for the metric tensor in the Coordinates constructor + Coordinates coords{mesh, + FieldMetric{1.0}, // dx + FieldMetric{1.0}, // dy + FieldMetric{1.0}, // dz + FieldMetric{0.0}, // J + FieldMetric{0.0}, // Bxy + FieldMetric{0.0}, // g11 + FieldMetric{0.0}, // g22 + FieldMetric{0.0}, // g33 + FieldMetric{0.0}, // g12 + FieldMetric{0.0}, // g13 + FieldMetric{0.0}, // g23 + FieldMetric{1.0}, // g_11 + FieldMetric{1.0}, // g_22 + FieldMetric{1.0}, // g_23 + FieldMetric{0.0}, // g_12 + FieldMetric{0.0}, // g_13 + FieldMetric{0.0}, // g_23 + FieldMetric{0.0}, // ShiftTorsion + FieldMetric{0.0}}; // IntShiftTorsion + + // Modify covariant components + constexpr double g_11 = 1.0; + constexpr double g_22 = 1.0; + constexpr double g_33 = 1.0; + const double g_12 = sqrt(3.0) / 4.0; // (std::sqrt only constexpr since C++26) + constexpr double g_13 = 0.5; + const double g_23 = sqrt(3.0) / 4.0; // (std::sqrt only constexpr since C++26) + auto updated_metric_tensor = CovariantMetricTensor(g_11, g_22, g_33, g_12, g_13, g_23); + coords.setCovariantMetricTensor(updated_metric_tensor); + + // Check that the contravariant components have been calculated corrected + constexpr double expected_g11 = 13.0 / 9.0; + constexpr double expected_g22 = 4.0 / 3.0; + constexpr double expected_g33 = 13.0 / 9.0; + const double expected_g12 = -2.0 * sqrt(3.0) / 9.0; + constexpr double expected_g13 = -5.0 / 9.0; + const double expected_g23 = -2.0 * sqrt(3.0) / 9.0; + + EXPECT_TRUE(IsFieldEqual(coords.g11(), expected_g11)); + EXPECT_TRUE(IsFieldEqual(coords.g22(), expected_g22)); + EXPECT_TRUE(IsFieldEqual(coords.g33(), expected_g33)); + EXPECT_TRUE(IsFieldEqual(coords.g12(), expected_g12)); + EXPECT_TRUE(IsFieldEqual(coords.g13(), expected_g13)); + EXPECT_TRUE(IsFieldEqual(coords.g23(), expected_g23)); +} + +TEST_F(CoordinatesTest, GetCovariantMetricTensor) { + Coordinates coords{mesh, + FieldMetric{1.0}, // dx + FieldMetric{1.0}, // dy + FieldMetric{1.0}, // dz + FieldMetric{0.0}, // J + FieldMetric{0.0}, // Bxy + FieldMetric{1.2}, // g11 + FieldMetric{2.3}, // g22 + FieldMetric{3.4}, // g33 + FieldMetric{4.5}, // g12 + FieldMetric{5.6}, // g13 + FieldMetric{6.7}, // g23 + FieldMetric{9.7}, // g_11 + FieldMetric{7.5}, // g_22 + FieldMetric{4.7}, // g_23 + FieldMetric{3.9}, // g_12 + FieldMetric{1.7}, // g_13 + FieldMetric{5.3}, // g_23 + FieldMetric{0.0}, // ShiftTorsion + FieldMetric{0.0}}; // IntShiftTorsion + + EXPECT_TRUE(IsFieldEqual(coords.g_11(), 9.7)); + EXPECT_TRUE(IsFieldEqual(coords.g_22(), 7.5)); + EXPECT_TRUE(IsFieldEqual(coords.g_33(), 4.7)); + EXPECT_TRUE(IsFieldEqual(coords.g_12(), 3.9)); + EXPECT_TRUE(IsFieldEqual(coords.g_13(), 1.7)); + EXPECT_TRUE(IsFieldEqual(coords.g_23(), 5.3)); +} + +TEST_F(CoordinatesTest, SetCovariantMetricTensor) { + { + // Set initial values for the metric tensor in the Coordinates constructor + Coordinates coords{mesh, + FieldMetric{1.0}, // dx + FieldMetric{1.0}, // dy + FieldMetric{1.0}, // dz + FieldMetric{0.0}, // J + FieldMetric{0.0}, // Bxy + FieldMetric{0.0}, // g11 + FieldMetric{0.0}, // g22 + FieldMetric{0.0}, // g33 + FieldMetric{0.0}, // g12 + FieldMetric{0.0}, // g13 + FieldMetric{0.0}, // g23 + FieldMetric{1.0}, // g_11 + FieldMetric{1.0}, // g_22 + FieldMetric{1.0}, // g_23 + FieldMetric{0.0}, // g_12 + FieldMetric{0.0}, // g_13 + FieldMetric{0.0}, // g_23 + FieldMetric{0.0}, // ShiftTorsion + FieldMetric{0.0}}; // IntShiftTorsion + + // Modify with setter + auto updated_metric_tensor = CovariantMetricTensor(1.0, 2.0, 0.4, 1.0, 0.0, 0.2); + coords.setCovariantMetricTensor(updated_metric_tensor); + + // Get values with getter and check they have been modified as expected + EXPECT_TRUE(IsFieldEqual(coords.g_11(), 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.g_22(), 2.0)); + EXPECT_TRUE(IsFieldEqual(coords.g_33(), 0.4)); + EXPECT_TRUE(IsFieldEqual(coords.g_12(), 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.g_13(), 0.0)); + EXPECT_TRUE(IsFieldEqual(coords.g_23(), 0.2)); + } +} + +TEST_F(CoordinatesTest, IndexedAccessors) { + + int x = mesh->xstart; + int y = mesh->ystart; +#if BOUT_USE_METRIC_3D + int z = mesh->LocalNz; +#endif + + output_info.disable(); + output_warn.disable(); + Coordinates coords(mesh); + output_warn.enable(); + output_info.enable(); + + const auto& dx = coords.dx(); + const auto& dy = coords.dy(); +#if BOUT_USE_METRIC_3D + const auto& dz = coords.dz(); +#endif + +#if not(BOUT_USE_METRIC_3D) + const BoutReal expected_dx = dx(x, y); + const BoutReal expected_dy = dy(x, y); +#else + const BoutReal expected_dx = dx(x, y, z); + const BoutReal expected_dy = dy(x, y, z); + const BoutReal expected_dz = dz(x, y, z); +#endif + +#if not(BOUT_USE_METRIC_3D) + const FieldMetric& actual_dx = coords.dx(x, y); + const FieldMetric& actual_dy = coords.dy(x, y); +#else + const Field3D& actual_dx = coords.dx(x, y, z); + const Field3D& actual_dy = coords.dy(x, y, z); + const Field3D& actual_dz = coords.dz(x, y, z); +#endif + + EXPECT_EQ(actual_dx, expected_dx); + EXPECT_EQ(actual_dy, expected_dy); +#if BOUT_USE_METRIC_3D + EXPECT_EQ(actual_dz, expected_dz); +#endif +} diff --git a/tests/unit/mesh/test_coordinates_accessor.cxx b/tests/unit/mesh/test_coordinates_accessor.cxx index ccdd031e4e..0e4c594643 100644 --- a/tests/unit/mesh/test_coordinates_accessor.cxx +++ b/tests/unit/mesh/test_coordinates_accessor.cxx @@ -83,13 +83,21 @@ TEST_F(CoordinatesAccessorTest, ClearBoth) { FieldMetric{0.0}, // g_23 FieldMetric{0.0}, // ShiftTorsion FieldMetric{0.0}}; // IntShiftTorsion - // Need to set geometry information - coords.G1 = coords.G2 = coords.G3 = 0.2; - coords.non_uniform = true; - coords.d1_dx = coords.d1_dy = coords.d1_dz = 0.1; + coords.setNon_uniform(true); + coords.setD1_dx(0.1); + coords.setD1_dy(0.1); + coords.setD1_dz(0.1); #if BOUT_USE_METRIC_3D - coords.Bxy.splitParallelSlices(); - coords.Bxy.yup() = coords.Bxy.ydown() = coords.Bxy; + + FieldMetric mutable_Bxy = coords.Bxy(); + mutable_Bxy.splitParallelSlices(); + coords.setBxy(mutable_Bxy); + + mutable_Bxy = coords.Bxy(); + mutable_Bxy.yup() = coords.Bxy(); + mutable_Bxy.ydown() = coords.Bxy(); + coords.setBxy(mutable_Bxy); + #endif CoordinatesAccessor acc(mesh->getCoordinates()); @@ -123,13 +131,21 @@ TEST_F(CoordinatesAccessorTest, ClearOneTwo) { FieldMetric{0.0}, // g_23 FieldMetric{0.0}, // ShiftTorsion FieldMetric{0.0}}; // IntShiftTorsion - // Need to set geometry information - coords.G1 = coords.G2 = coords.G3 = 0.2; - coords.non_uniform = true; - coords.d1_dx = coords.d1_dy = coords.d1_dz = 0.1; + coords.setNon_uniform(true); + coords.setD1_dx(0.1); + coords.setD1_dy(0.1); + coords.setD1_dz(0.1); #if BOUT_USE_METRIC_3D - coords.Bxy.splitParallelSlices(); - coords.Bxy.yup() = coords.Bxy.ydown() = coords.Bxy; + + FieldMetric mutable_Bxy = coords.Bxy(); + mutable_Bxy.splitParallelSlices(); + coords.setBxy(mutable_Bxy); + + mutable_Bxy = coords.Bxy(); + mutable_Bxy.yup() = coords.Bxy(); + mutable_Bxy.ydown() = coords.Bxy(); + coords.setBxy(mutable_Bxy); + #endif CoordinatesAccessor acc(mesh->getCoordinates()); @@ -165,13 +181,21 @@ TEST_F(CoordinatesAccessorTest, ClearTwoOneNone) { FieldMetric{0.0}, // g_23 FieldMetric{0.0}, // ShiftTorsion FieldMetric{0.0}}; // IntShiftTorsion - // Need to set geometry information - coords.G1 = coords.G2 = coords.G3 = 0.2; - coords.non_uniform = true; - coords.d1_dx = coords.d1_dy = coords.d1_dz = 0.1; + coords.setNon_uniform(true); + coords.setD1_dx(0.1); + coords.setD1_dy(0.1); + coords.setD1_dz(0.1); #if BOUT_USE_METRIC_3D - coords.Bxy.splitParallelSlices(); - coords.Bxy.yup() = coords.Bxy.ydown() = coords.Bxy; + + FieldMetric mutable_Bxy = coords.Bxy(); + mutable_Bxy.splitParallelSlices(); + coords.setBxy(mutable_Bxy); + + mutable_Bxy = coords.Bxy(); + mutable_Bxy.yup() = coords.Bxy(); + mutable_Bxy.ydown() = coords.Bxy(); + coords.setBxy(mutable_Bxy); + #endif CoordinatesAccessor acc(mesh->getCoordinates()); diff --git a/tests/unit/mesh/test_interpolation.cxx b/tests/unit/mesh/test_interpolation.cxx index 62a23a0db1..b90fc78da9 100644 --- a/tests/unit/mesh/test_interpolation.cxx +++ b/tests/unit/mesh/test_interpolation.cxx @@ -77,7 +77,6 @@ class Field3DInterpToTest : public ::testing::Test { Field2D{0.0, mesh}, Field2D{0.0, mesh}, Field2D{0.0, mesh}, Field2D{0.0, mesh}), location); - // No call to Coordinates::geometry() needed here mesh->getCoordinates(location)->setParallelTransform( bout::utils::make_unique(*mesh)); } @@ -324,7 +323,6 @@ class Field2DInterpToTest : public ::testing::Test { Field2D{0.0, mesh}, Field2D{0.0, mesh}, Field2D{0.0, mesh}, Field2D{0.0, mesh}), location); - // No call to Coordinates::geometry() needed here mesh->getCoordinates(location)->setParallelTransform( bout::utils::make_unique(*mesh)); } diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index 700b977ac8..48ca39e2bd 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -339,7 +339,7 @@ public: /// Take an rvalue (e.g. initializer list), convert to lvalue and delegate constructor FakeGridDataSource(Options&& values) : FakeGridDataSource(values) {} - bool hasVar(const std::string& UNUSED(name)) override { return false; } + bool hasVar(const std::string& name) override { return values.isSet(name); } bool get([[maybe_unused]] Mesh* m, std::string& sval, const std::string& name, const std::string& def = "") override { @@ -441,21 +441,24 @@ public: Field2D{0.0}, Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}); - // Set some auxilliary variables - // Usually set in geometry() - // Note: For testing these are set to non-zero values - test_coords->G1 = test_coords->G2 = test_coords->G3 = 0.1; - // Set nonuniform corrections - test_coords->non_uniform = true; - test_coords->d1_dx = test_coords->d1_dy = 0.2; - test_coords->d1_dz = 0.0; + test_coords->setNon_uniform(true); + test_coords->setD1_dx(0.2); + test_coords->setD1_dy(0.2); + test_coords->setD1_dz(0.0); #if BOUT_USE_METRIC_3D - test_coords->Bxy.splitParallelSlices(); - test_coords->Bxy.yup() = test_coords->Bxy.ydown() = test_coords->Bxy; + + FieldMetric mutable_Bxy = test_coords->Bxy(); + mutable_Bxy.splitParallelSlices(); + test_coords->setBxy(mutable_Bxy); + + mutable_Bxy = test_coords->Bxy(); + mutable_Bxy.yup() = test_coords->Bxy(); + mutable_Bxy.ydown() = test_coords->Bxy(); + test_coords->setBxy(mutable_Bxy); + #endif - // No call to Coordinates::geometry() needed here static_cast(bout::globals::mesh)->setCoordinates(test_coords); static_cast(bout::globals::mesh) ->setGridDataSource(new FakeGridDataSource()); @@ -486,21 +489,24 @@ public: Field2D{0.0, mesh_staggered}, Field2D{0.0, mesh_staggered}, Field2D{0.0, mesh_staggered}); - // Set some auxilliary variables - test_coords_staggered->G1 = test_coords_staggered->G2 = test_coords_staggered->G3 = - 0.1; - // Set nonuniform corrections - test_coords_staggered->non_uniform = true; - test_coords_staggered->d1_dx = test_coords_staggered->d1_dy = 0.2; - test_coords_staggered->d1_dz = 0.0; + test_coords_staggered->setNon_uniform(true); + test_coords_staggered->setD1_dx(0.2); + test_coords_staggered->setD1_dy(0.2); + test_coords_staggered->setD1_dz(0.0); #if BOUT_USE_METRIC_3D - test_coords_staggered->Bxy.splitParallelSlices(); - test_coords_staggered->Bxy.yup() = test_coords_staggered->Bxy.ydown() = - test_coords_staggered->Bxy; + + mutable_Bxy = test_coords_staggered->Bxy(); + mutable_Bxy.splitParallelSlices(); + test_coords_staggered->setBxy(mutable_Bxy); + + mutable_Bxy = test_coords_staggered->Bxy(); + mutable_Bxy.yup() = test_coords_staggered->Bxy(); + mutable_Bxy.ydown() = test_coords_staggered->Bxy(); + test_coords_staggered->setBxy(mutable_Bxy); + #endif - // No call to Coordinates::geometry() needed here test_coords_staggered->setParallelTransform( bout::utils::make_unique(*mesh_staggered)); diff --git a/tools/pylib/_boutpp_build/boutcpp.pxd.jinja b/tools/pylib/_boutpp_build/boutcpp.pxd.jinja index 8f838b864c..fab475c52a 100644 --- a/tools/pylib/_boutpp_build/boutcpp.pxd.jinja +++ b/tools/pylib/_boutpp_build/boutcpp.pxd.jinja @@ -78,10 +78,6 @@ cdef extern from "bout/coordinates.hxx": {{ metric_field }} G1, G2, G3 {{ metric_field }} ShiftTorsion {{ metric_field }} IntShiftTorsion - int geometry() - int calcCovariant() - int calcContravariant() - int jacobian() cdef extern from "bout/fieldgroup.hxx": cppclass FieldGroup: diff --git a/tools/pylib/_boutpp_build/boutpp.pyx.jinja b/tools/pylib/_boutpp_build/boutpp.pyx.jinja index 9aedbb291a..58edd0db7f 100644 --- a/tools/pylib/_boutpp_build/boutpp.pyx.jinja +++ b/tools/pylib/_boutpp_build/boutpp.pyx.jinja @@ -769,7 +769,7 @@ cdef class Mesh: Usefull if the Options are in SI units, but the simulation is written in Bohm units. Calling it multiple times will not change the mesh, if the normalisation is always the same. - It calls mesh->dx/=norm etc. followed by a call to geometry(). + It calls mesh->dx()/=norm etc. followed by a call to geometry(). Parameters ---------- @@ -818,7 +818,6 @@ cdef Mesh meshFromPtr(c.Mesh * obj): cdef Coordinates coordsFromPtr(c.Coordinates * obj): coords = Coordinates() coords.cobj = obj - coords._setmembers() coords.isSelfOwned = False return coords @@ -828,26 +827,22 @@ cdef class Coordinates: """ cdef c.Coordinates * cobj cdef c.bool isSelfOwned - cdef public {{ metric_field }} dx, dy, dz - cdef public {{ metric_field }} J - cdef public {{ metric_field }} Bxy - cdef public {{ metric_field }} g11, g22, g33, g12, g13, g23 - cdef public {{ metric_field }} g_11, g_22, g_33, g_12, g_13, g_23 - cdef public {{ metric_field }} G1_11, G1_22, G1_33, G1_12, G1_13, G1_23 - cdef public {{ metric_field }} G2_11, G2_22, G2_33, G2_12, G2_13, G2_23 - cdef public {{ metric_field }} G3_11, G3_22, G3_33, G3_12, G3_13, G3_23 - cdef public {{ metric_field }} G1, G2, G3 - cdef public {{ metric_field }} ShiftTorsion - cdef public {{ metric_field }} IntShiftTorsion + cdef {{ metric_field }} dx, dy, dz + cdef {{ metric_field }} J + cdef {{ metric_field }} Bxy + cdef {{ metric_field }} g11, g22, g33, g12, g13, g23 + cdef {{ metric_field }} g_11, g_22, g_33, g_12, g_13, g_23 + cdef {{ metric_field }} G1_11, G1_22, G1_33, G1_12, G1_13, G1_23 + cdef {{ metric_field }} G2_11, G2_22, G2_33, G2_12, G2_13, G2_23 + cdef {{ metric_field }} G3_11, G3_22, G3_33, G3_12, G3_13, G3_23 + cdef {{ metric_field }} G1, G2, G3 + cdef {{ metric_field }} ShiftTorsion + cdef {{ metric_field }} IntShiftTorsion def __init__(self): self.cobj = NULL self.isSelfOwned = False - def _setmembers(self): -{% for f in "dx", "dy", "dz", "J", "Bxy", "g11", "g22", "g33", "g12", "g13", "g23", "g_11", "g_22", "g_33", "g_12", "g_13", "g_23", "G1_11", "G1_22", "G1_33", "G1_12", "G1_13", "G1_23", "G2_11", "G2_22", "G2_33", "G2_12", "G2_13", "G2_23", "G3_11", "G3_22", "G3_33", "G3_12", "G3_13", "G3_23", "G1", "G2", "G3", "ShiftTorsion", "IntShiftTorsion" %} - self.{{f}} = {{ metric_field.fdd }}FromPtr(&self.cobj.{{f}}) -{% endfor %} def __dealloc__(self): self._boutpp_dealloc() diff --git a/tools/pylib/_boutpp_build/helper.cxx.jinja b/tools/pylib/_boutpp_build/helper.cxx.jinja index fdaa944f3e..a611bc813d 100644 --- a/tools/pylib/_boutpp_build/helper.cxx.jinja +++ b/tools/pylib/_boutpp_build/helper.cxx.jinja @@ -170,8 +170,7 @@ Mesh * c_get_global_mesh(){ void c_mesh_normalise(Mesh * msh, double norm){ //printf("%g\n",norm); auto coord = msh->getCoordinates(); - coord->dx /= norm; - coord->dy /= norm; - coord->dz /= norm; - coord->geometry(); + coord->setDx(coord->dx() / norm); + coord->setDy(coord->dy() / norm); + coord->setDz(coord->dz() / norm); }