diff --git a/CMakeLists.txt b/CMakeLists.txt index 5f054c1c1f..78584ddac2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -382,6 +382,12 @@ 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 ) diff --git a/examples/6field-simple/elm_6f.cxx b/examples/6field-simple/elm_6f.cxx index 24256333df..1778644833 100644 --- a/examples/6field-simple/elm_6f.cxx +++ b/examples/6field-simple/elm_6f.cxx @@ -357,7 +357,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); @@ -701,7 +701,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 @@ -863,7 +863,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) { @@ -1047,24 +1047,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 @@ -1442,11 +1443,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 b27ae97113..3cb7cc0aec 100644 --- a/examples/dalf3/dalf3.cxx +++ b/examples/dalf3/dalf3.cxx @@ -1,6 +1,6 @@ /**************************************************************** * DALF3 model - * + * * Four-field model for electron pressure, vorticity, A|| and * parallel velocity * @@ -240,29 +240,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 3cc5227b30..9254cb7362 100644 --- a/examples/elm-pb-outerloop/elm_pb_outerloop.cxx +++ b/examples/elm-pb-outerloop/elm_pb_outerloop.cxx @@ -815,7 +815,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 @@ -952,7 +952,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) { @@ -1082,24 +1082,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 @@ -1670,12 +1671,12 @@ class ELMpb : public PhysicsModel { #endif }; - // Terms which are not yet single index operators - // Note: Terms which are included in the single index loop - // may be commented out here, to allow comparison/testing + // Terms which are not yet single index operators + // Note: Terms which are included in the single index loop + // may be commented out here, to allow comparison/testing - //////////////////////////////////////////////////// - // Parallel electric field + //////////////////////////////////////////////////// + // Parallel electric field #if not EVOLVE_JPAR // Vector potential @@ -1782,11 +1783,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"); @@ -1897,7 +1898,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 2cb373c52b..c61a0da8c9 100644 --- a/examples/elm-pb/elm_pb.cxx +++ b/examples/elm-pb/elm_pb.cxx @@ -770,7 +770,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 @@ -907,7 +907,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) { @@ -1037,24 +1037,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 @@ -1356,7 +1357,8 @@ class ELMpb : public PhysicsModel { // Only update if simulation time has advanced // Uses an exponential decay of the weighting of the value in the boundary // so that the solution is well behaved for arbitrary steps - BoutReal const weight = exp(-(t - phi_boundary_last_update) / phi_boundary_timescale); + const BoutReal weight = + exp(-(t - phi_boundary_last_update) / phi_boundary_timescale); phi_boundary_last_update = t; if (mesh->firstX()) { @@ -1385,11 +1387,11 @@ class ELMpb : public PhysicsModel { } // Old value of phi at boundary. Note: this is constant in Z - BoutReal const oldvalue = + const BoutReal oldvalue = 0.5 * (phi(mesh->xstart - 1, j, 0) + phi(mesh->xstart, j, 0)); // New value of phi at boundary, relaxing towards phivalue - BoutReal const newvalue = weight * oldvalue + (1. - weight) * phivalue; + const BoutReal newvalue = weight * oldvalue + (1. - weight) * phivalue; // Set phi at the boundary to this value for (int k = mesh->zstart; k <= mesh->zend; k++) { @@ -1412,7 +1414,7 @@ class ELMpb : public PhysicsModel { 0.5 * (phi(mesh->xend + 1, j, 0) + phi(mesh->xend, j, 0)); // New value of phi at boundary, relaxing towards phivalue - BoutReal const newvalue = weight * oldvalue + (1. - weight) * phivalue; + const BoutReal newvalue = weight * oldvalue + (1. - weight) * phivalue; // Set phi at the boundary to this value for (int k = mesh->zstart; k <= mesh->zend; k++) { @@ -1625,7 +1627,7 @@ class ELMpb : public PhysicsModel { for (int jz = 0; jz < mesh->LocalNz; jz++) { // Zero-gradient potential - BoutReal const phisheath = phi_fa(r.ind, mesh->ystart, jz); + const BoutReal phisheath = phi_fa(r.ind, mesh->ystart, jz); BoutReal jsheath = -(sqrt(mi_me) / (2. * sqrt(PI))) * phisheath; @@ -1646,7 +1648,7 @@ class ELMpb : public PhysicsModel { for (int jz = 0; jz < mesh->LocalNz; jz++) { // Zero-gradient potential - BoutReal const phisheath = phi_fa(r.ind, mesh->yend, jz); + const BoutReal phisheath = phi_fa(r.ind, mesh->yend, jz); BoutReal jsheath = (sqrt(mi_me) / (2. * sqrt(PI))) * phisheath; @@ -1804,11 +1806,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"); @@ -1946,7 +1948,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 } @@ -2068,7 +2070,8 @@ class ELMpb : public PhysicsModel { ddt(P).applyBoundary("neumann"); Field3D U1 = ddt(U); - U1 += (gamma * B0 * B0) * Grad_par(Jrhs, CELL_CENTRE) + (gamma * b0xcv) * Grad(ddt(P)); + U1 += + (gamma * B0 * B0) * Grad_par(Jrhs, CELL_CENTRE) + (gamma * b0xcv) * Grad(ddt(P)); // Second matrix, solving Alfven wave dynamics static std::unique_ptr invU{nullptr}; 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 031931c1c4..a11ea11b1d 100644 --- a/examples/laplacexy/alfven-wave/alfven.cxx +++ b/examples/laplacexy/alfven-wave/alfven.cxx @@ -31,8 +31,8 @@ class Alfven : public PhysicsModel { BoutReal mu_epar; // Electron parallel viscosity BoutReal resistivity; - bool laplace_perp; // Use Laplace_perp or Delp2? - bool split_n0; // Split solve into n=0 and n~=0? + bool laplace_perp; // Use Laplace_perp or Delp2? + bool split_n0; // Split solve into n=0 and n~=0? std::unique_ptr laplacexy{nullptr}; // Laplacian solver in X-Y (n=0) bool newXZsolver; @@ -180,7 +180,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"; @@ -189,11 +189,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 @@ -203,23 +203,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 e3d9528d45..06d73fdbc7 100644 --- a/examples/laplacexy/laplace_perp/test.cxx +++ b/examples/laplacexy/laplace_perp/test.cxx @@ -30,24 +30,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..d79ba75a7f --- /dev/null +++ b/include/bout/christoffel_symbols.hxx @@ -0,0 +1,63 @@ +#ifndef BOUT_CHRISTOFFELSYMBOLS_HXX +#define BOUT_CHRISTOFFELSYMBOLS_HXX + +#include + +class Coordinates; + +class ChristoffelSymbols { + +public: + explicit ChristoffelSymbols(Coordinates& coordinates); + + const bout::FieldMetric& G1_11() const { return G1_11_m; } + const bout::FieldMetric& G1_22() const { return G1_22_m; } + const bout::FieldMetric& G1_33() const { return G1_33_m; } + const bout::FieldMetric& G1_12() const { return G1_12_m; } + const bout::FieldMetric& G1_13() const { return G1_13_m; } + const bout::FieldMetric& G1_23() const { return G1_23_m; } + + const bout::FieldMetric& G2_11() const { return G2_11_m; } + const bout::FieldMetric& G2_22() const { return G2_22_m; } + const bout::FieldMetric& G2_33() const { return G2_33_m; } + const bout::FieldMetric& G2_12() const { return G2_12_m; } + const bout::FieldMetric& G2_13() const { return G2_13_m; } + const bout::FieldMetric& G2_23() const { return G2_23_m; } + + const bout::FieldMetric& G3_11() const { return G3_11_m; } + const bout::FieldMetric& G3_22() const { return G3_22_m; } + const bout::FieldMetric& G3_33() const { return G3_33_m; } + const bout::FieldMetric& G3_12() const { return G3_12_m; } + const bout::FieldMetric& G3_13() const { return G3_13_m; } + const bout::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: + bout::FieldMetric G1_11_m, G1_22_m, G1_33_m, G1_12_m, G1_13_m, G1_23_m; + bout::FieldMetric G2_11_m, G2_22_m, G2_33_m, G2_12_m, G2_13_m, G2_23_m; + bout::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 e7ead42ee5..11cca18100 100644 --- a/include/bout/coordinates.hxx +++ b/include/bout/coordinates.hxx @@ -3,16 +3,16 @@ * * ChangeLog * ========= - * + * * 2014-11-10 Ben Dudson * * Created by separating metric from Mesh * - * + * ************************************************************************** * Copyright 2014-2025 BOUT++ contributors * * Contact: Ben Dudson, dudson2@llnl.gov - * + * * This file is part of BOUT++. * * BOUT++ is free software: you can redistribute it and/or modify @@ -35,27 +35,23 @@ #include #include +#include #include #include +#include +#include #include +#include + class Mesh; /*! * Represents a coordinate system, and associated operators - * - * This is a container for a collection of metric tensor components */ class Coordinates { public: -#if BOUT_USE_METRIC_3D - using FieldMetric = Field3D; -#else - using FieldMetric = Field2D; -#endif - - /// Standard constructor from input - Coordinates(Mesh* mesh, Options* options = nullptr); + using FieldMetric = bout::FieldMetric; /// Constructor interpolating from another Coordinates object /// By default attempts to read staggered Coordinates from grid data source, @@ -63,65 +59,207 @@ public: /// 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, bool communicate = true); + void setDy(FieldMetric dy, bool communicate = true); + void setDz(FieldMetric dz, bool communicate = true); + + 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 FieldMetric& g_11() const { return covariantMetricTensor.g11(); } + const FieldMetric& g_22() const { return covariantMetricTensor.g22(); } + const FieldMetric& g_33() const { return covariantMetricTensor.g33(); } + const FieldMetric& g_12() const { return covariantMetricTensor.g12(); } + const FieldMetric& g_13() const { return covariantMetricTensor.g13(); } + const FieldMetric& g_23() const { return covariantMetricTensor.g23(); } /// Contravariant metric tensor (g^{ij}) - FieldMetric g11, g22, g33, g12, g13, g23; + const FieldMetric& g11() const { return contravariantMetricTensor.g11(); } + const FieldMetric& g22() const { return contravariantMetricTensor.g22(); } + const FieldMetric& g33() const { return contravariantMetricTensor.g33(); } + const FieldMetric& g12() const { return contravariantMetricTensor.g12(); } + const FieldMetric& g13() const { return contravariantMetricTensor.g13(); } + const 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); + + void communicateMetricTensor(); - FieldMetric G1, G2, G3; + void communicateDz(); + + ///< 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, const bool communicate = true); + + void setBxy(FieldMetric Bxy, const bool communicate = true); /// 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 @@ -146,7 +284,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", @@ -154,11 +292,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", @@ -166,7 +304,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, @@ -219,36 +357,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 }; /* @@ -256,10 +506,10 @@ private: class TokamakCoordinates : public Coordinates { public: TokamakCoordinates(Mesh *mesh) : Coordinates(mesh) { - + } private: - + }; */ diff --git a/include/bout/fv_ops.hxx b/include/bout/fv_ops.hxx index 0ec1fbe3ad..b54951fe3e 100644 --- a/include/bout/fv_ops.hxx +++ b/include/bout/fv_ops.hxx @@ -100,7 +100,7 @@ struct Fromm { /*! * Second order slope limiter method - * + * * Limits slope to minimum absolute value * of left and right gradients. If at a maximum * or minimum slope set to zero, i.e. reverts @@ -137,8 +137,8 @@ private: /*! * Monotonised Central (MC) second order slope limiter (Van Leer) - * - * Limits the slope based on taking the slope with + * + * Limits the slope based on taking the slope with * the minimum absolute value from central, 2*left and * 2*right. If any of these slopes have different signs * then the slope reverts to zero (i.e. 1st-order upwinding). @@ -374,9 +374,9 @@ const Field3D Div_par(const Field3D& f_in, const Field3D& v_in, * Div ( n * v ) -- Magnetic drifts * * This uses the expression - * + * * Div( A ) = 1/J * d/di ( J * A^i ) - * + * * Hence the input vector should be contravariant * * Note: Uses to/from FieldAligned @@ -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..cbbd6d24ff --- /dev/null +++ b/include/bout/g_values.hxx @@ -0,0 +1,28 @@ +#ifndef BOUT_GVALUES_HXX +#define BOUT_GVALUES_HXX + +#include + +class Coordinates; + +/// `GValues` needs renaming, when we know what the name should be +class GValues { +public: + explicit GValues(const Coordinates& coordinates); + + const bout::FieldMetric& G1() const { return G1_m; } + const bout::FieldMetric& G2() const { return G2_m; } + const bout::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: + bout::FieldMetric G1_m, G2_m, G3_m; +}; + +#endif //BOUT_GVALUES_HXX diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 25e66fe5d2..1cdddd6749 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -57,6 +57,7 @@ class Mesh; #include "bout/region.hxx" #include "bout/sys/range.hxx" // RangeIterator #include "bout/unused.hxx" +#include #include #include @@ -181,6 +182,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 @@ -627,8 +642,17 @@ 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); + + inserted.first->second->communicateMetricTensor(); + inserted.first->second->communicateDz(); + return inserted.first->second; } @@ -714,8 +738,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 diff --git a/include/bout/metric_tensor.hxx b/include/bout/metric_tensor.hxx new file mode 100644 index 0000000000..cef9b74d04 --- /dev/null +++ b/include/bout/metric_tensor.hxx @@ -0,0 +1,117 @@ +#ifndef BOUT_METRIC_TENSOR_HXX +#define BOUT_METRIC_TENSOR_HXX + +#include +#include +#include +#include + +#include +#include + +namespace bout { +#if BOUT_USE_METRIC_3D +using FieldMetric = Field3D; +#else +using FieldMetric = Field2D; +#endif +} // namespace bout + +class MetricTensor { +public: +#if BOUT_USE_METRIC_3D + using Metric2DSlice = const BoutReal*; +#else + using Metric2DSlice = const BoutReal&; +#endif + using FieldMetric = bout::FieldMetric; + + 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", + const bool communicate = true); + + // 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); + } + + void communicate() const; + +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 d653d96d68..89aa86b9a2 100644 --- a/include/bout/physicsmodel.hxx +++ b/include/bout/physicsmodel.hxx @@ -1,20 +1,20 @@ /*!************************************************************************ * \file physicsmodel.hxx - * + * * @brief Base class for Physics Models - * - * + * + * * * Changelog: - * + * * 2013-08 Ben Dudson * * Initial version - * + * ************************************************************************** * Copyright 2013 B.D.Dudson * * Contact: Ben Dudson, bd512@york.ac.uk - * + * * This file is part of BOUT++. * * BOUT++ is free software: you can redistribute it and/or modify @@ -81,6 +81,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); } @@ -167,9 +171,9 @@ public: * * Output * ------ - * + * * The time derivatives will be put in the ddt() variables - * + * * Returns a flag: 0 indicates success, non-zero an error flag */ int runRHS(BoutReal time, bool linear = false); @@ -203,7 +207,7 @@ public: bool hasPrecon(); /*! - * Run the preconditioner. The system state should be in the + * Run the preconditioner. The system state should be in the * evolving variables, and the vector to be solved in the ddt() variables. * The result will be put in the ddt() variables. * @@ -219,7 +223,7 @@ public: /*! * Run the Jacobian-vector multiplication function - * + * * Note: this is usually only called by the Solver */ int runJacobian(BoutReal t); @@ -241,10 +245,10 @@ protected: // The init and rhs functions are implemented by user code to specify problem /*! * @brief This function is called once by the solver at the start of a simulation. - * + * * A valid PhysicsModel must implement this function - * - * Variables should be read from the inputs, and the variables to + * + * Variables should be read from the inputs, and the variables to * be evolved should be specified. */ virtual int init(bool restarting) = 0; @@ -258,7 +262,7 @@ protected: /*! * @brief This function is called by the time integration solver * at least once per time step - * + * * Variables being evolved will be set by the solver * before the call, and this function must calculate * and set the time-derivatives. @@ -278,10 +282,10 @@ protected: /// Add additional variables other than the evolving variables to the restart files virtual void restartVars(Options& options); - /* + /* If split operator is set to true, then convective() and diffusive() are called instead of rhs() - + For implicit-explicit schemes, convective() will typically be treated explicitly, whilst diffusive() will be treated implicitly. For unsplit methods, both convective and diffusive will be called @@ -334,7 +338,7 @@ protected: * * @param[in] var The variable to evolve * @param[in] name The name to use for variable initialisation and output - * + * * Note that the variable must not be destroyed (e.g. go out of scope) * after this call, since a pointer to \p var is stored in the solver. * @@ -358,11 +362,11 @@ protected: * Specify a constrained variable \p var, which will be * adjusted to make \p F_var equal to zero. * If the solver does not support constraints then this will throw an exception - * + * * @param[in] var The variable the solver should modify * @param[in] F_var The control variable, which the user will set * @param[in] name The name to use for initialisation and output - * + * */ bool bout_constrain(Field3D& var, Field3D& F_var, const char* name); @@ -491,8 +495,7 @@ private: /// Add fields to the solver. /// This should accept up to ten arguments -#define SOLVE_FOR(...) \ - { MACRO_FOR_EACH(SOLVE_FOR1, __VA_ARGS__) } +#define SOLVE_FOR(...) {MACRO_FOR_EACH(SOLVE_FOR1, __VA_ARGS__)} /// Write this variable once to the grid file #define SAVE_ONCE1(var) dump.addOnce(var, #var); @@ -532,8 +535,7 @@ private: dump.addOnce(var6, #var6); \ } -#define SAVE_ONCE(...) \ - { MACRO_FOR_EACH(SAVE_ONCE1, __VA_ARGS__) } +#define SAVE_ONCE(...) {MACRO_FOR_EACH(SAVE_ONCE1, __VA_ARGS__)} /// Write this variable every timestep #define SAVE_REPEAT1(var) dump.addRepeat(var, #var); @@ -573,7 +575,6 @@ private: dump.addRepeat(var6, #var6); \ } -#define SAVE_REPEAT(...) \ - { MACRO_FOR_EACH(SAVE_REPEAT1, __VA_ARGS__) } +#define SAVE_REPEAT(...) {MACRO_FOR_EACH(SAVE_REPEAT1, __VA_ARGS__)} #endif // BOUT_PHYSICS_MODEL_H 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 9154f78a4f..3ef38ef746 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -728,7 +728,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 1677187fcd..6f2888d98a 100644 --- a/src/field/vecops.cxx +++ b/src/field/vecops.cxx @@ -6,7 +6,7 @@ * Copyright 2010 B.D.Dudson, S.Farley, M.V.Umansky, X.Q.Xu * * Contact: Ben Dudson, bd512@york.ac.uk - * + * * This file is part of BOUT++. * * BOUT++ is free software: you can redistribute it and/or modify @@ -105,10 +105,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()); @@ -127,9 +127,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()); @@ -160,10 +160,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; } @@ -186,7 +186,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 @@ -195,9 +195,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; } @@ -225,10 +225,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; } @@ -249,10 +249,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; } @@ -273,12 +273,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()); @@ -301,12 +301,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()); @@ -386,80 +386,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 ab2d993549..38df949d9f 100644 --- a/src/field/vector2d.cxx +++ b/src/field/vector2d.cxx @@ -2,7 +2,7 @@ * Class for 2D vectors. Built on the Field2D class, * all operators relating to vectors are here (none in Field classes) * - * As with Field2D, Vector2D are constant in z (toroidal angle) + * As with Field2D, Vector2D are constant in z (toroidal angle) * * B.Dudson, October 2007 * @@ -10,7 +10,7 @@ * Copyright 2010 B.D.Dudson, S.Farley, M.V.Umansky, X.Q.Xu * * Contact: Ben Dudson, bd512@york.ac.uk - * + * * This file is part of BOUT++. * * BOUT++ is free software: you can redistribute it and/or modify @@ -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; @@ -197,7 +204,7 @@ Vector2D* Vector2D::timeDeriv() { } /*************************************************************** - * OPERATORS + * OPERATORS ***************************************************************/ /////////////////// ASSIGNMENT //////////////////// @@ -303,7 +310,7 @@ Vector2D& Vector2D::operator/=(const Field2D& rhs) { } /*************************************************************** - * BINARY OPERATORS + * BINARY OPERATORS ***************************************************************/ ////////////////// ADDITION ////////////////////// @@ -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 7fb4a88918..e700d1ab64 100644 --- a/src/field/vector3d.cxx +++ b/src/field/vector3d.cxx @@ -10,7 +10,7 @@ * Copyright 2010 B.D.Dudson, S.Farley, M.V.Umansky, X.Q.Xu * * Contact: Ben Dudson, bd512@york.ac.uk - * + * * This file is part of BOUT++. * * BOUT++ is free software: you can redistribute it and/or modify @@ -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; @@ -199,7 +204,7 @@ Vector3D* Vector3D::timeDeriv() { } /*************************************************************** - * OPERATORS + * OPERATORS ***************************************************************/ /////////////////// ASSIGNMENT //////////////////// @@ -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; \ @@ -393,7 +398,7 @@ CROSS(Vector3D, Vector2D, Vector3D) CROSS(Vector2D, Vector2D, Vector2D) /*************************************************************** - * BINARY OPERATORS + * BINARY OPERATORS ***************************************************************/ ////////////////// ADDITION ////////////////////// @@ -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/hypre3d/hypre3d_laplace.cxx b/src/invert/laplace/impls/hypre3d/hypre3d_laplace.cxx index c50be1db85..1aca52cada 100644 --- a/src/invert/laplace/impls/hypre3d/hypre3d_laplace.cxx +++ b/src/invert/laplace/impls/hypre3d/hypre3d_laplace.cxx @@ -106,8 +106,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; @@ -118,8 +118,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; @@ -130,8 +130,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) != 0) { // 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; @@ -142,8 +142,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) != 0) { // 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; @@ -276,7 +276,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 auto 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. @@ -285,18 +285,18 @@ 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]; - 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) { @@ -304,32 +304,32 @@ void LaplaceHypre3d::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 +360,24 @@ 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]; - 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,14 +385,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 @@ -402,10 +402,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 4be5bfbad3..7feac07771 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx +++ b/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx @@ -1,5 +1,5 @@ /************************************************************************** - * Perpendicular Laplacian inversion. + * Perpendicular Laplacian inversion. * Using Geometrical Multigrid Solver * * Equation solved is: @@ -9,7 +9,7 @@ * Copyright 2016 K.S. Kang * * Contact: Ben Dudson, bd512@york.ac.uk - * + * * This file is part of BOUT++. * * BOUT++ is free software: you can redistribute it and/or modify @@ -214,7 +214,9 @@ LaplaceMultigrid::LaplaceMultigrid(Options* opt, const CELL_LOC loc, Mesh* mesh_ } BOUT_OMP_SAFE(parallel) BOUT_OMP_SAFE(master) - { output << "Num threads = " << omp_get_num_threads() << endl; } + { + output << "Num threads = " << omp_get_num_threads() << endl; + } } } @@ -613,7 +615,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 bf8711245e..b827a5a478 100644 --- a/src/invert/laplace/impls/naulin/naulin_laplace.cxx +++ b/src/invert/laplace/impls/naulin/naulin_laplace.cxx @@ -288,8 +288,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/petsc/petsc_laplace.cxx b/src/invert/laplace/impls/petsc/petsc_laplace.cxx index 89ba25405b..880471f7b3 100644 --- a/src/invert/laplace/impls/petsc/petsc_laplace.cxx +++ b/src/invert/laplace/impls/petsc/petsc_laplace.cxx @@ -403,16 +403,16 @@ FieldPerp LaplacePetsc::solve(const FieldPerp& b, const FieldPerp& x0) { LaplacePetsc::CoeffsA LaplacePetsc::Coeffs(Ind3D i) { const auto x = i.x(); - BoutReal coef1 = coords->g11[i]; // X 2nd derivative coefficient - BoutReal coef2 = coords->g33[i]; // Z 2nd derivative coefficient - BoutReal coef3 = 2. * coords->g13[i]; // X-Z mixed derivative coefficient + BoutReal coef1 = coords->g11()[i]; // X 2nd derivative coefficient + BoutReal coef2 = coords->g33()[i]; // Z 2nd derivative coefficient + BoutReal coef3 = 2. * coords->g13()[i]; // X-Z mixed derivative coefficient BoutReal coef4 = 0.0; BoutReal coef5 = 0.0; // If global flag all_terms are set (true by default) if (all_terms) { - coef4 = coords->G1[i]; // X 1st derivative - coef5 = coords->G3[i]; // Z 1st derivative + coef4 = coords->G1()[i]; // X 1st derivative + coef5 = coords->G3()[i]; // Z 1st derivative ASSERT3(std::isfinite(coef4)); ASSERT3(std::isfinite(coef5)); @@ -421,14 +421,15 @@ LaplacePetsc::CoeffsA LaplacePetsc::Coeffs(Ind3D i) { if (nonuniform) { // non-uniform mesh correction if ((x != 0) && (x != (localmesh->LocalNx - 1))) { - coef4 -= 0.5 * ((coords->dx[i.xp()] - coords->dx[i.xm()]) / SQ(coords->dx[i])) + coef4 -= 0.5 * ((coords->dx()[i.xp()] - coords->dx()[i.xm()]) / SQ(coords->dx()[i])) * coef1; // BOUT-06 term } } if (localmesh->IncIntShear) { // d2dz2 term - coef2 += coords->g11[i] * coords->IntShiftTorsion[i] * coords->IntShiftTorsion[i]; + coef2 += + coords->g11()[i] * coords->IntShiftTorsion()[i] * coords->IntShiftTorsion()[i]; // Mixed derivative coef3 = 0.0; // This cancels out } @@ -450,19 +451,19 @@ LaplacePetsc::CoeffsA LaplacePetsc::Coeffs(Ind3D i) { if (fourth_order) { // Fourth order discretization of C in x ddx_C = (-C2[i.xpp()] + (8. * C2[i.xp()]) - (8. * C2[i.xm()]) + C2[i.xmm()]) - / (12. * coords->dx[i] * (C1[i])); + / (12. * coords->dx()[i] * (C1[i])); // Fourth order discretization of C in z ddz_C = (-C2[i.zpp()] + (8. * C2[i.zp()]) - (8. * C2[i.zm()]) + C2[i.zmm()]) - / (12. * coords->dz[i] * (C1[i])); + / (12. * coords->dz()[i] * (C1[i])); } else { // Second order discretization of C in x - ddx_C = (C2[i.xp()] - C2[i.xm()]) / (2. * coords->dx[i] * (C1[i])); + ddx_C = (C2[i.xp()] - C2[i.xm()]) / (2. * coords->dx()[i] * (C1[i])); // Second order discretization of C in z - ddz_C = (C2[i.zp()] - C2[i.zm()]) / (2. * coords->dz[i] * (C1[i])); + ddz_C = (C2[i.zp()] - C2[i.zm()]) / (2. * coords->dz()[i] * (C1[i])); } - coef4 += (coords->g11[i] * ddx_C) + (coords->g13[i] * ddz_C); - coef5 += (coords->g13[i] * ddx_C) + (coords->g33[i] * ddz_C); + coef4 += (coords->g11()[i] * ddx_C) + (coords->g13()[i] * ddz_C); + coef5 += (coords->g13()[i] * ddx_C) + (coords->g33()[i] * ddz_C); } } @@ -487,8 +488,8 @@ void LaplacePetsc::setSecondOrderMatrix(int y, bool inner_X_neumann, bool outer_X_neumann) { // Set the boundaries if (inner_X_neumann) { - const auto dx = sliceXZ(coords->dx, y); - const auto g11 = sliceXZ(coords->g11, y); + const auto dx = sliceXZ(coords->dx(), y); + const auto g11 = sliceXZ(coords->g11(), y); BOUT_FOR_SERIAL(i, indexer->getRegionInnerX()) { const auto factor = 1. / dx[i] / std::sqrt(g11[i]); @@ -502,8 +503,8 @@ void LaplacePetsc::setSecondOrderMatrix(int y, bool inner_X_neumann, } } if (outer_X_neumann) { - const auto dx = sliceXZ(coords->dx, y); - const auto g11 = sliceXZ(coords->g11, y); + const auto dx = sliceXZ(coords->dx(), y); + const auto g11 = sliceXZ(coords->g11(), y); BOUT_FOR_SERIAL(i, indexer->getRegionOuterX()) { const auto factor = 1. / dx[i] / std::sqrt(g11[i]); @@ -535,9 +536,9 @@ void LaplacePetsc::setSecondOrderMatrix(int y, bool inner_X_neumann, ASSERT3(std::isfinite(A4)); ASSERT3(std::isfinite(A5)); - const BoutReal dx = coords->dx[i]; + const BoutReal dx = coords->dx()[i]; const BoutReal dx2 = SQ(dx); - const BoutReal dz = coords->dz[i]; + const BoutReal dz = coords->dz()[i]; const BoutReal dz2 = SQ(dz); const BoutReal dxdz = dx * dz; operator2D(l, l) = A0 - (2.0 * ((A1 / dx2) + (A2 / dz2))); @@ -557,8 +558,8 @@ void LaplacePetsc::setFourthOrderMatrix(int y, bool inner_X_neumann, // Set boundaries if (inner_X_neumann) { - const auto dx = sliceXZ(coords->dx, y); - const auto g11 = sliceXZ(coords->g11, y); + const auto dx = sliceXZ(coords->dx(), y); + const auto g11 = sliceXZ(coords->g11(), y); BOUT_FOR_SERIAL(i, indexer->getRegionInnerX()) { const auto factor = 1. / dx[i] / std::sqrt(g11[i]); @@ -579,8 +580,8 @@ void LaplacePetsc::setFourthOrderMatrix(int y, bool inner_X_neumann, } if (outer_X_neumann) { - const auto dx = sliceXZ(coords->dx, y); - const auto g11 = sliceXZ(coords->g11, y); + const auto dx = sliceXZ(coords->dx(), y); + const auto g11 = sliceXZ(coords->g11(), y); BOUT_FOR_SERIAL(i, indexer->getRegionOuterX()) { const auto factor = 1. / dx[i] / std::sqrt(g11[i]); @@ -618,9 +619,9 @@ void LaplacePetsc::setFourthOrderMatrix(int y, bool inner_X_neumann, ASSERT3(std::isfinite(A4)); ASSERT3(std::isfinite(A5)); - const BoutReal dx = coords->dx[i]; + const BoutReal dx = coords->dx()[i]; const BoutReal dx2 = SQ(dx); - const BoutReal dz = coords->dz[i]; + const BoutReal dz = coords->dz()[i]; const BoutReal dz2 = SQ(dz); const BoutReal dxdz = dx * dz; diff --git a/src/invert/laplace/impls/petsc3damg/petsc3damg.cxx b/src/invert/laplace/impls/petsc3damg/petsc3damg.cxx index 3be5e43e63..79566505b1 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()) { @@ -274,7 +278,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. @@ -283,18 +287,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) { @@ -302,32 +306,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; @@ -359,24 +363,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]; @@ -384,15 +388,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 @@ -402,10 +406,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 e9182042de..45dd36eded 100644 --- a/src/invert/laplace/invert_laplace.cxx +++ b/src/invert/laplace/invert_laplace.cxx @@ -104,7 +104,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); @@ -261,7 +261,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/impls/hypre/laplacexy-hypre.cxx b/src/invert/laplacexy/impls/hypre/laplacexy-hypre.cxx index 439d07a4e5..fbba16673c 100644 --- a/src/invert/laplacexy/impls/hypre/laplacexy-hypre.cxx +++ b/src/invert/laplacexy/impls/hypre/laplacexy-hypre.cxx @@ -23,8 +23,10 @@ #include #if BOUT_HAS_CUDA && defined(__CUDACC__) -#define gpuErrchk(ans) \ - { gpuAssert((ans), __FILE__, __LINE__); } +#define gpuErrchk(ans) \ + { \ + gpuAssert((ans), __FILE__, __LINE__); \ + } inline void gpuAssert(cudaError_t code, const char* file, int line, bool abort = true) { if (code != cudaSuccess) { fprintf(stderr, "GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line); @@ -111,20 +113,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 @@ -137,27 +139,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/laplacexy/impls/petsc/laplacexy-petsc.cxx b/src/invert/laplacexy/impls/petsc/laplacexy-petsc.cxx index 04abecfe05..881a0b7fc0 100644 --- a/src/invert/laplacexy/impls/petsc/laplacexy-petsc.cxx +++ b/src/invert/laplacexy/impls/petsc/laplacexy-petsc.cxx @@ -906,13 +906,13 @@ void LaplaceXYpetsc::setMatrixElementsFiniteVolume(const Field2D& A, const Field // (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++) { @@ -1017,17 +1017,17 @@ void LaplaceXYpetsc::setMatrixElementsFiniteDifference(const Field2D& A, // + 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/laplacexy/impls/petsc2/laplacexy-petsc2.cxx b/src/invert/laplacexy/impls/petsc2/laplacexy-petsc2.cxx index 01019466a8..bdfc3bb5ff 100644 --- a/src/invert/laplacexy/impls/petsc2/laplacexy-petsc2.cxx +++ b/src/invert/laplacexy/impls/petsc2/laplacexy-petsc2.cxx @@ -157,20 +157,20 @@ void LaplaceXYpetsc2::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 @@ -183,28 +183,28 @@ void LaplaceXYpetsc2::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/laplacexz/impls/cyclic/laplacexz-cyclic.cxx b/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx index b3e619df0c..0a7030dec9 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 c32c3d4b2d..6f432e3bcc 100644 --- a/src/invert/parderiv/impls/cyclic/cyclic.cxx +++ b/src/invert/parderiv/impls/cyclic/cyclic.cxx @@ -1,14 +1,14 @@ /************************************************************************ * Inversion of parallel derivatives - * - * Inverts a matrix of the form + * + * Inverts a matrix of the form * * A + B * Grad2_par2 + C*D2DYDZ + + D*D2DZ2 + E*DDY - * + * * Parallel algorithm, using Cyclic Reduction * * Author: Ben Dudson, University of York, Oct 2011 - * + * * Known issues: * ------------ * @@ -17,7 +17,7 @@ * Copyright 2010 B.D.Dudson, S.Farley, M.V.Umansky, X.Q.Xu * * Contact: Ben Dudson, bd512@york.ac.uk - * + * * This file is part of BOUT++. * * BOUT++ is free software: you can redistribute it and/or modify @@ -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 aad01c5f2f..b5aee9d0a1 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 2e079f59b3..600c5dadc9 100644 --- a/src/mesh/boundary_standard.cxx +++ b/src/mesh/boundary_standard.cxx @@ -2672,8 +2672,8 @@ 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] - c0[jz] *= exp(coef * kwave); // The decaying solution only + jz * 2.0 * PI / metric->zlength(x, y); // wavenumber in [rad^-1] + c0[jz] *= exp(coef * kwave); // The decaying solution only } // Reverse FFT irfft(c0.begin(), mesh->LocalNz, f(x, y)); @@ -2977,13 +2977,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..9eb4e767a9 --- /dev/null +++ b/src/mesh/christoffel_symbols.cxx @@ -0,0 +1,115 @@ +#include "bout/christoffel_symbols.hxx" +#include "bout/coordinates.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 * coordinates.DDX(g_11) + + g12 * (coordinates.DDX(g_12) - 0.5 * coordinates.DDY(g_11)) + + g13 * (coordinates.DDX(g_13) - 0.5 * coordinates.DDZ(g_11)); + G1_22_m = g11 * (coordinates.DDY(g_12) - 0.5 * coordinates.DDX(g_22)) + + 0.5 * g12 * coordinates.DDY(g_22) + + g13 * (coordinates.DDY(g_23) - 0.5 * coordinates.DDZ(g_22)); + G1_33_m = g11 * (coordinates.DDZ(g_13) - 0.5 * coordinates.DDX(g_33)) + + g12 * (coordinates.DDZ(g_23) - 0.5 * coordinates.DDY(g_33)) + + 0.5 * g13 * coordinates.DDZ(g_33); + G1_12_m = + 0.5 * g11 * coordinates.DDY(g_11) + 0.5 * g12 * coordinates.DDX(g_22) + + 0.5 * g13 + * (coordinates.DDY(g_13) + coordinates.DDX(g_23) - coordinates.DDZ(g_12)); + G1_13_m = + 0.5 * g11 * coordinates.DDZ(g_11) + + 0.5 * g12 + * (coordinates.DDZ(g_12) + coordinates.DDX(g_23) - coordinates.DDY(g_13)) + + 0.5 * g13 * coordinates.DDX(g_33); + G1_23_m = + 0.5 * g11 * (coordinates.DDZ(g_12) + coordinates.DDY(g_13) - coordinates.DDX(g_23)) + + 0.5 * g12 + * (coordinates.DDZ(g_22) + coordinates.DDY(g_23) - coordinates.DDY(g_23)) + // + 0.5 *g13*(coordinates.DDZ(g_32) + coordinates.DDY(g_33) - coordinates.DDZ(g_23)); + // which equals + + 0.5 * g13 * coordinates.DDY(g_33); + + G2_11_m = 0.5 * g12 * coordinates.DDX(g_11) + + g22 * (coordinates.DDX(g_12) - 0.5 * coordinates.DDY(g_11)) + + g23 * (coordinates.DDX(g_13) - 0.5 * coordinates.DDZ(g_11)); + G2_22_m = g12 * (coordinates.DDY(g_12) - 0.5 * coordinates.DDX(g_22)) + + 0.5 * g22 * coordinates.DDY(g_22) + + g23 * (coordinates.DDY(g23) - 0.5 * coordinates.DDZ(g_22)); + G2_33_m = g12 * (coordinates.DDZ(g_13) - 0.5 * coordinates.DDX(g_33)) + + g22 * (coordinates.DDZ(g_23) - 0.5 * coordinates.DDY(g_33)) + + 0.5 * g23 * coordinates.DDZ(g_33); + G2_12_m = + 0.5 * g12 * coordinates.DDY(g_11) + 0.5 * g22 * coordinates.DDX(g_22) + + 0.5 * g23 + * (coordinates.DDY(g_13) + coordinates.DDX(g_23) - coordinates.DDZ(g_12)); + G2_13_m = + // 0.5 *g21*(coordinates.DDZ(g_11) + coordinates.DDX(covariantMetricTensor.Getg13()) - coordinates.DDX(g_13)) + // which equals + 0.5 * g12 * (coordinates.DDZ(g_11) + coordinates.DDX(g_13) - coordinates.DDX(g_13)) + // + 0.5 *g22*(coordinates.DDZ(covariantMetricTensor.Getg21()) + coordinates.DDX(g_23) - coordinates.DDY(g_13)) + // which equals + + 0.5 * g22 + * (coordinates.DDZ(g_12) + coordinates.DDX(g_23) - coordinates.DDY(g_13)) + // + 0.5 *g23*(coordinates.DDZ(covariantMetricTensor.Getg31()) + coordinates.DDX(g_33) - coordinates.DDZ(g_13)); + // which equals + + 0.5 * g23 * coordinates.DDX(g_33); + G2_23_m = + 0.5 * g12 * (coordinates.DDZ(g_12) + coordinates.DDY(g_13) - coordinates.DDX(g_23)) + + 0.5 * g22 * coordinates.DDZ(g_22) + 0.5 * g23 * coordinates.DDY(g_33); + + G3_11_m = 0.5 * g13 * coordinates.DDX(g_11) + + g23 * (coordinates.DDX(g_12) - 0.5 * coordinates.DDY(g_11)) + + g33 * (coordinates.DDX(g_13) - 0.5 * coordinates.DDZ(g_11)); + G3_22_m = g13 * (coordinates.DDY(g_12) - 0.5 * coordinates.DDX(g_22)) + + 0.5 * g23 * coordinates.DDY(g_22) + + g33 * (coordinates.DDY(g_23) - 0.5 * coordinates.DDZ(g_22)); + G3_33_m = g13 * (coordinates.DDZ(g_13) - 0.5 * coordinates.DDX(g_33)) + + g23 * (coordinates.DDZ(g_23) - 0.5 * coordinates.DDY(g_33)) + + 0.5 * g33 * coordinates.DDZ(g_33); + G3_12_m = + // 0.5 *g31*(coordinates.DDY(g_11) + coordinates.DDX(covariantMetricTensor.Getg12()) - coordinates.DDX(g_12)) + // which equals to + 0.5 * g13 * coordinates.DDY(g_11) + // + 0.5 *g32*(coordinates.DDY(covariantMetricTensor.Getg21()) + coordinates.DDX(g_22) - coordinates.DDY(g_12)) + // which equals to + + 0.5 * g23 * coordinates.DDX(g_22) + //+ 0.5 *g33*(coordinates.DDY(covariantMetricTensor.Getg31()) + coordinates.DDX(covariantMetricTensor.Getg32()) - coordinates.DDZ(g_12)); + // which equals to + + 0.5 * g33 * (coordinates.DDY(g_13)) + coordinates.DDX(g_23) + - coordinates.DDZ(g_12); + G3_13_m = + 0.5 * g13 * coordinates.DDZ(g_11) + + 0.5 * g23 + * (coordinates.DDZ(g_12) + coordinates.DDX(g_23) - coordinates.DDY(g_13)) + + 0.5 * g33 * coordinates.DDX(g_33); + G3_23_m = 0.5 * g13 * (coordinates.DDZ(g_12) + coordinates.DDY(g_13)) + - coordinates.DDX(g_23) + 0.5 * g23 * coordinates.DDZ(g_22) + + 0.5 * g33 * coordinates.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 d2634d3f88..2696db4380 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -4,6 +4,8 @@ * given the contravariant metric tensor terms **************************************************************************/ +#include "bout/field2d.hxx" +#include "bout/g_values.hxx" #include #include #include @@ -12,29 +14,90 @@ #include #include -#include +#include "parallel/fci.hxx" +#include "parallel/shiftedmetricinterp.hxx" +#include "bout/derivs.hxx" #include #include #include -#include - -#include "invert3x3.hxx" -#include "parallel/fci.hxx" -#include "parallel/shiftedmetricinterp.hxx" +#include namespace { + +// 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 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 @@ -147,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; @@ -174,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 { @@ -302,99 +366,178 @@ 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 + localmesh->communicate_no_slices(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) { + setParallelTransform(mesh_options); + + setMetricTensor(coords_in->getContravariantMetricTensor(), + coords_in->getCovariantMetricTensor()); + + const std::function + 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(); - if (options == nullptr) { - options = Options::getRoot()->getSection("mesh"); + setJ(interpolateAndExtrapolate(coords_in->J(), location, true, true, false, + transform.get()), + false); + setBxy(interpolateAndExtrapolate(coords_in->Bxy(), location, true, true, false, + transform.get()), + false); + + 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()); +} + +// 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 = - (*options)["extrapolate_x"].withDefault(not mesh->sourceHasXBoundaryGuards()); - const bool extrapolate_y = - (*options)["extrapolate_y"].withDefault(not mesh->sourceHasYBoundaryGuards()); + 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 " @@ -406,976 +549,372 @@ 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) { - mesh->communicate_no_slices(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_, false); + setDy(dy_, false); + setDz(dz_, false); + // 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)); + + // More robust to extrapolate derived quantities directly, rather than + // deriving from extrapolated covariant metric components - // Off-diagonal elements. Default to 0 - g12 = getUnalignedAtLocation(g12, "g12", 0.0); - g13 = getUnalignedAtLocation(g13, "g13", 0.0); - g23 = getUnalignedAtLocation(g23, "g23", 0.0); + const std::function + 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("RGN_ALL", false)); + 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))); + output_warn.write("\tMaximum difference in J is {:e}\n", max(abs(J() - J_from_file))); + setJ(J_from_file, false); - mesh->communicate_no_slices(J); - - // 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()), + false); + // 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(), false); } 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, false); + 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()), + false); + // 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) { - mesh->communicate_no_slices(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()); - - 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"); +FieldMetric Coordinates::getDzFromOptionsFile(Mesh* mesh, + const std::string& suffix) const { - ShiftTorsion = interpolateAndExtrapolate(coords_in->ShiftTorsion, location, true, - true, false, transform.get()); + 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); - 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"); + const Timer 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) { - - localmesh->communicate_no_slices(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, const bool communicate) { if (min(abs(dx)) < 1e-8) { throw BoutException("dx magnitude less than 1e-8"); } + dx_ = std::move(dx); + if (communicate) { + localmesh->communicate(dx_); + } +} +void Coordinates::setDy(FieldMetric dy, const bool communicate) { if (min(abs(dy)) < 1e-8) { throw BoutException("dy magnitude less than 1e-8"); } + dy_ = std::move(dy); + if (communicate) { + localmesh->communicate(dy_); + } +} +void Coordinates::setDz(FieldMetric dz, const bool communicate) { if (min(abs(dz)) < 1e-8) { throw BoutException("dz magnitude less than 1e-8"); } + dz_ = std::move(dz); + if (communicate) { + 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; - localmesh->communicate_no_slices(tmp); - G1 = (DDX(J * g11) + DDY(tmp) + DDZ(J * g13)) / J; - tmp = J * g22; - localmesh->communicate_no_slices(tmp); - G2 = (DDX(J * g12) + DDY(tmp) + DDZ(J * g23)) / J; - tmp = J * g23; - localmesh->communicate_no_slices(tmp); - G3 = (DDX(J * g13) + DDY(tmp) + DDZ(J * g33)) / J; - - // Communicate christoffel symbol terms - output_progress.write("\tCommunicating connection terms\n"); - - localmesh->communicate_no_slices(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 - - // 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) - - localmesh->communicate_no_slices(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) - - localmesh->communicate_no_slices(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); - localmesh->communicate_no_slices(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) - - localmesh->communicate_no_slices(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) - - localmesh->communicate_no_slices(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); - - localmesh->communicate_no_slices(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()); + christoffel_symbols_cache.reset(); + g_values_cache.reset(); - d1_dz = -d2z / (dz * dz); - } -#else - d1_dz = 0; -#endif - } - localmesh->communicate_no_slices(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) { - - // 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 (const auto det = bout::invert3x3(a); det.has_value()) { - output_error.write("\tERROR: metric tensor is singular at {}, determinant: {:e}\n", - i, det.value()); - 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))); +void Coordinates::correctionForNonUniformMeshes(bool force_interpolate_from_centre) { + OPTION(Options::getRoot(), non_uniform_, true); - output_info.write("\tLocal maximum error in off-diagonal inversion is {:e}\n", maxerr); + FieldMetric d2x(localmesh); + FieldMetric d2y(localmesh); + FieldMetric d2z(localmesh); // d^2 x / d i^2 - return 0; -} - -int Coordinates::calcContravariant(const std::string& region) { - - // Make sure metric elements are allocated - g11.allocate(); - g22.allocate(); - g33.allocate(); - g12.allocate(); - g13.allocate(); - g23.allocate(); - - // 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, g_11.getRegion(region)) { - a(0, 0) = g_11[i]; - a(1, 1) = g_22[i]; - a(2, 2) = g_33[i]; - - 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]; - - if (const auto det = bout::invert3x3(a); det.has_value()) { - output_error.write("\tERROR: metric tensor is singular at {}, determinant: {:e}\n", - i, det.value()); - return 1; - } - - g11[i] = a(0, 0); - g22[i] = a(1, 1); - g33[i] = a(2, 2); + // Read correction for non-uniform meshes + const std::string suffix = getLocationSuffix(location); - g12[i] = a(0, 1); - g13[i] = a(0, 2); - g23[i] = a(1, 2); + 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(); } - 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))); + 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) - output_info.write("\tMaximum 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("\tMaximum error in off-diagonal inversion is {:e}\n", maxerr); - return 0; -} - -int Coordinates::jacobian() { + 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()); - // calculate Jacobian using g^-1 = det[g^ij], J = sqrt(g) + d1_dx_ = -d2x / (dx() * dx()); + } - const bool extrapolate_x = not localmesh->sourceHasXBoundaryGuards(); - const bool extrapolate_y = not localmesh->sourceHasYBoundaryGuards(); + 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_ = DDY(1. / dy()); // d/di(1/dy) - auto g = g11 * g22 * g33 + 2.0 * g12 * g13 * g23 - g11 * g23 * g23 - g22 * g13 * g13 - - g33 * g12 * g12; + 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()); - // Check that g is positive - bout::checkPositive(g, "The determinant of g^ij", "RGN_NOBNDRY"); + d1_dy_ = -d2y / (dy() * dy()); + } - 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()); +#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()); - Bxy = sqrt(g_22) / J; - Bxy = interpolateAndExtrapolate(Bxy, location, extrapolate_x, extrapolate_y, false, - transform.get()); + d1_dz_ = -d2z / (dz() * dz()); + } +#else + d1_dz_ = 0; +#endif - return 0; + localmesh->communicate(d1_dx_, d1_dy_, d1_dz_); } -namespace { -// Utility function for fixing up guard cells of zShift -void fixZShiftGuards(Field2D& zShift) { - auto localmesh = zShift.getMesh(); +FieldMetric Coordinates::recalculateJacobian() const { + 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(); - // 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 - localmesh->communicate_no_slices(zShift); + bout::checkPositive(g_matrix, "The determinant of g^ij", "RGN_NOBNDRY"); - // 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; - } - } + return 1. / sqrt(g_matrix); + } catch (const BoutException& e) { + output_error.write("\tError in jacobian call\n"); + throw e; } } -} // namespace -void Coordinates::setParallelTransform(Options* options) { +FieldMetric Coordinates::recalculateBxy() const { return sqrt(g_22()) / J(); } + +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"); @@ -1387,20 +926,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); + const std::string 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"); } @@ -1412,9 +953,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"); } @@ -1431,12 +972,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."); @@ -1444,13 +990,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'")); } /******************************************************************************* @@ -1460,19 +1006,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; @@ -1482,12 +1028,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); @@ -1495,12 +1042,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) { @@ -1509,17 +1056,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)) { ASSERT1(location == outloc || (outloc == CELL_DEFAULT && location == var.getLocation())); @@ -1538,9 +1083,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(); @@ -1563,9 +1108,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, @@ -1575,12 +1120,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 - const auto& Bxy_floc = f.getCoordinates()->Bxy; + const 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 @@ -1590,7 +1135,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); } ///////////////////////////////////////////////////////// @@ -1603,7 +1148,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; } @@ -1618,7 +1163,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; @@ -1637,9 +1182,7 @@ Coordinates::FieldMetric Coordinates::Delp2(const Field2D& f, CELL_LOC outloc, 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) { @@ -1655,7 +1198,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)}; @@ -1698,9 +1241,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); @@ -1724,7 +1268,7 @@ FieldPerp Coordinates::Delp2(const FieldPerp& f, CELL_LOC outloc, bool useFFT) { FieldPerp result{emptyFrom(f).setLocation(outloc)}; - int jy = f.getIndex(); + const int jy = f.getIndex(); result.setIndex(jy); if (useFFT and localmesh->getNZPE() == 1) { @@ -1771,12 +1315,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 @@ -1787,13 +1332,11 @@ Coordinates::FieldMetric Coordinates::Laplace(const Field2D& f, CELL_LOC outloc, 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, @@ -1802,23 +1345,20 @@ Field3D Coordinates::Laplace(const Field3D& f, CELL_LOC outloc, 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 { #if not(BOUT_USE_METRIC_3D) Field2D result; result.allocate(); @@ -1828,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]); } @@ -1876,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; @@ -1887,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; @@ -1904,106 +1478,65 @@ 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)); - } - } +FieldMetric& Coordinates::J() const { + if (jacobian_cache == nullptr) { + jacobian_cache = std::make_unique(recalculateJacobian()); } - // 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)); - } - } + return *jacobian_cache; +} + +void Coordinates::setJ(const FieldMetric& J, const bool communicate) { + 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); + if (communicate) { + localmesh->communicate(*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::setBxy(FieldMetric Bxy, const bool communicate) { + //TODO: Calculate Bxy and check value is close + Bxy_ = std::move(Bxy); + if (communicate) { + 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); +} + +void Coordinates::communicateMetricTensor() { + contravariantMetricTensor.communicate(); + covariantMetricTensor.communicate(); +} + +void Coordinates::communicateDz() { localmesh->communicate(dz_); } diff --git a/src/mesh/coordinates_accessor.cxx b/src/mesh/coordinates_accessor.cxx index 0ce4b664b5..aac7a012cf 100644 --- a/src/mesh/coordinates_accessor.cxx +++ b/src/mesh/coordinates_accessor.cxx @@ -1,7 +1,6 @@ #include "bout/coordinates_accessor.hxx" -#include - #include "bout/mesh.hxx" +#include "bout/metric_tensor.hxx" #include @@ -18,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); @@ -42,24 +41,25 @@ 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(...) \ - { MACRO_FOR_EACH(COPY_STRIPE1, __VA_ARGS__) } +#define COPY_STRIPE(...) \ + { \ + MACRO_FOR_EACH(COPY_STRIPE1, __VA_ARGS__) \ + } // 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 09433b0685..1571c4f0a3 100644 --- a/src/mesh/difops.cxx +++ b/src/mesh/difops.cxx @@ -83,7 +83,7 @@ Field3D Grad_parP(const Field3D& apar, const Field3D& f) { Field3D result{emptyFrom(f)}; - int ncz = mesh->LocalNz; + const int ncz = mesh->LocalNz; Coordinates* metric = apar.getCoordinates(); @@ -105,17 +105,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; + const int zm = (z - 1 + ncz) % ncz; + const int 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)); + const 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)); // 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)); + const 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)); // Now calculate (bx*d/dx + by*d/dy + bz*d/dz) f @@ -250,19 +250,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)); + const BoutReal fL = 0.5 * (f(i, j, k) + f.ydown()(i, j - 1, k)); + const BoutReal 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)); + const BoutReal fR = 0.5 * (f(i, j, k) + f.yup()(i, j + 1, k)); + const BoutReal vR = 0.5 * (v(i, j, k) + v.yup()(i, j + 1, k)); // Calculate flux at right boundary (y+1/2) - BoutReal fluxRight = + const BoutReal 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 = + const BoutReal 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))); @@ -281,10 +281,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 @@ -293,7 +293,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, @@ -466,16 +466,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); + const Coordinates::FieldMetric dpdx = DDX(phi, outloc); + const Coordinates::FieldMetric dpdy = DDY(phi, outloc); // Calculate advection velocity - Coordinates::FieldMetric vx = -metric->g_23 * dpdy; - Coordinates::FieldMetric vy = metric->g_23 * dpdx; + const Coordinates::FieldMetric vx = -metric->g_23() * dpdy; + const Coordinates::FieldMetric 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); @@ -498,24 +498,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); + const Coordinates::FieldMetric dpdx = DDX(phi, outloc); + const Coordinates::FieldMetric 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; + const Coordinates::FieldMetric vx = -metric->g_23() * dpdy; + const Coordinates::FieldMetric 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 + ")"; @@ -537,19 +537,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); + const Field3D dpdx = DDX(p, outloc); + const Field3D dpdy = DDY(p, outloc); + const Field3D 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; + const Field3D vx = metric->g_22() * dpdz - metric->g_23() * dpdy; + const Field3D 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 + ")"; @@ -573,23 +573,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); + const Field3D dpdx = DDX(phi, outloc); + const Field3D dpdy = DDY(phi, outloc); + const Field3D 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; + const Field3D vx = metric->g_22() * dpdz - metric->g_23() * dpdy; + const Field3D 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 + ")"; @@ -623,7 +623,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; } @@ -658,13 +658,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; + const int zm = (z - 1 + ncz) % ncz; + const int 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)); + const BoutReal 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)); @@ -698,7 +698,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; @@ -770,7 +770,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; @@ -783,7 +783,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(); @@ -805,7 +805,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(); } } @@ -842,7 +842,7 @@ Field3D bracket(const Field3D& f, const Field3D& g, BRACKET_METHOD method, } // Get current timestep - BoutReal dt = solver->getCurrentTimestep(); + const BoutReal dt = solver->getCurrentTimestep(); FieldPerp vx(mesh), vz(mesh); vx.allocate(); @@ -850,7 +850,7 @@ Field3D bracket(const Field3D& f, const Field3D& g, BRACKET_METHOD method, vz.allocate(); vz.setLocation(outloc); - int ncz = mesh->LocalNz; + const int ncz = mesh->LocalNz; for (int y = mesh->ystart; y <= mesh->yend; y++) { for (int x = 1; x <= mesh->LocalNx - 2; x++) { for (int z = mesh->zstart; z <= mesh->zend; z++) { @@ -874,8 +874,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; + const int zm = (z - 1 + ncz) % ncz; + const int zp = (z + 1) % ncz; BoutReal gp, gm; @@ -948,7 +948,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; @@ -1046,7 +1046,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 fab8beb794..84a0b5c182 100644 --- a/src/mesh/fv_ops.cxx +++ b/src/mesh/fv_ops.cxx @@ -33,8 +33,8 @@ Field3D Div_a_Grad_perp(const Field3D& a, const Field3D& f) { // Flux in x - int xs = mesh->xstart - 1; - int xe = mesh->xend; + const int xs = mesh->xstart - 1; + const int xe = mesh->xend; /* if(mesh->firstX()) @@ -50,11 +50,11 @@ Field3D Div_a_Grad_perp(const Field3D& a, const Field3D& f) { for (int k = mesh->zstart; k <= mesh->zend; 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)); + const 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)); 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)); @@ -68,9 +68,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?"); } } @@ -86,12 +86,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); @@ -155,7 +155,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) @@ -185,7 +185,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()); + const bool 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"); @@ -209,30 +209,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]); + const BoutReal c = 0.5 * (K[i] + Kup[iyp]); // K at the upper boundary + const BoutReal J = 0.5 * (coord->J()[i] + coord->J()[iyp]); // Jacobian at boundary + const BoutReal 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]); + const BoutReal gradient = + 2. * (fup[iyp] - f[i]) / (coord->dy()[i] + coord->dy()[iyp]); - BoutReal flux = c * J * gradient / g_22; + const BoutReal 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 + const BoutReal c = 0.5 * (K[i] + Kdown[iym]); // K at the lower boundary + const BoutReal 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]); + const BoutReal 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]); + const BoutReal gradient = + 2. * (f[i] - fdown[iym]) / (coord->dy()[i] + coord->dy()[iym]); - BoutReal flux = c * J * gradient / g_22; + const BoutReal flux = c * J * gradient / g_22; - result[i] -= flux / (coord->dy[i] * coord->J[i]); + result[i] -= flux / (coord->dy()[i] * coord->J()[i]); } } @@ -263,9 +265,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); + const bool yperiodic = mesh->periodicY(i); + const bool has_upper_boundary = !yperiodic && mesh->lastY(i); + const bool has_lower_boundary = !yperiodic && mesh->firstY(i); // Always calculate fluxes at upper Y cell boundary const int ystart = @@ -284,15 +286,15 @@ const Field3D D4DY4(const Field3D& d_in, const Field3D& f_in) { BoutReal dy3 = SQ(coord->dy(i, j, k)) * coord->dy(i, j, k); // 3rd derivative at upper boundary - BoutReal d3fdy3 = + const BoutReal 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; + const 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; - 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)); } } } @@ -313,10 +315,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); + const bool yperiodic = mesh->periodicY(i); - bool has_upper_boundary = !yperiodic && mesh->lastY(i); - bool has_lower_boundary = !yperiodic && mesh->firstY(i); + const bool has_upper_boundary = !yperiodic && mesh->lastY(i); + const bool has_lower_boundary = !yperiodic && mesh->firstY(i); for (int j = mesh->ystart; j <= mesh->yend; j++) { @@ -330,13 +332,13 @@ const Field3D D4DY4_Index(const Field3D& f_in, bool bndry_flux) { for (int k = mesh->zstart; k <= mesh->zend; 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 @@ -354,13 +356,13 @@ const Field3D D4DY4_Index(const Field3D& f_in, bool bndry_flux) { for (int k = mesh->zstart; k <= mesh->zend; 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 @@ -383,13 +385,13 @@ const Field3D D4DY4_Index(const Field3D& f_in, bool bndry_flux) { if (j != mesh->ystart || !has_lower_boundary) { for (int k = mesh->zstart; k <= mesh->zend; 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 = @@ -402,13 +404,13 @@ const Field3D D4DY4_Index(const Field3D& f_in, bool bndry_flux) { // On a domain (Y) boundary for (int k = mesh->zstart; k <= mesh->zend; 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 @@ -436,7 +438,7 @@ void communicateFluxes(Field3D& f) { throw BoutException("communicateFluxes: Sorry!"); } - int size = mesh->LocalNy * mesh->LocalNz; + const int size = mesh->LocalNy * mesh->LocalNz; comm_handle xin, xout; // Cache results to silence spurious compiler warning about xin, // xout possibly being uninitialised when used @@ -503,12 +505,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); + const int kp = (k + 1) % (mesh->LocalNz); + const int km = (k - 1 + mesh->LocalNz) % (mesh->LocalNz); // Calculate gradients on cell faces -- assumes constant grid spacing - BoutReal gR = + const BoutReal 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)) @@ -516,7 +518,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 = + const BoutReal 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)) @@ -524,13 +526,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 = + const BoutReal 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 = + const BoutReal 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..c855063447 --- /dev/null +++ b/src/mesh/g_values.cxx @@ -0,0 +1,28 @@ +#include "bout/g_values.hxx" +#include "bout/coordinates.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 = (coordinates.DDX(J * g11) + coordinates.DDY(tmp) + coordinates.DDZ(J * g13)) / J; + tmp = J * g22; + Coordinates::communicate(tmp); + G2_m = (coordinates.DDX(J * g12) + coordinates.DDY(tmp) + coordinates.DDZ(J * g23)) / J; + tmp = J * g23; + Coordinates::communicate(tmp); + G3_m = (coordinates.DDX(J * g13) + coordinates.DDY(tmp) + coordinates.DDZ(J * g33)) / J; + + G1_m.getMesh()->communicate(G1_m, G2_m, G3_m); +} diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 9a98b5848a..cfe81ab0d4 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -210,6 +210,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); @@ -312,10 +338,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 @@ -540,12 +576,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 { @@ -752,8 +787,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); } } @@ -843,3 +884,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..f0abb49151 --- /dev/null +++ b/src/mesh/metric_tensor.cxx @@ -0,0 +1,140 @@ +#include "bout/metric_tensor.hxx" +#include "invert3x3.hxx" +#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 +#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, const bool communicate) { + // 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 (const auto det = bout::invert3x3(matrix); det.has_value()) { + throw BoutException("ERROR: metric tensor is singular at ({}, {}), determinant: {}", + i.x(), i.y(), det.value()); + } + + 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); + if (communicate) { + MetricTensor::communicate(); + } + return MetricTensor(g_11, g_22, g_33, g_12, g_13, g_23); +} + +void MetricTensor::communicate() const { + // copy to non-const variables (because communicate() cannot take const references) + auto tmp = g11_m; + auto tmp2 = g22_m; + auto tmp3 = g33_m; + auto tmp4 = g12_m; + auto tmp5 = g13_m; + auto tmp6 = g23_m; + g11_m.getMesh()->communicate(tmp, tmp2, tmp3, tmp4, tmp5, tmp6); +} diff --git a/src/physics/smoothing.cxx b/src/physics/smoothing.cxx index 1b437b4352..b643a016c8 100644 --- a/src/physics/smoothing.cxx +++ b/src/physics/smoothing.cxx @@ -4,15 +4,15 @@ * * 2014-10-29 Ben Dudson * * Moving averaging routines here from Mesh - * + * * 2010-05-17 Ben Dudson * * Added nonlinear filter - * + * ************************************************************** * Copyright 2010 B.D.Dudson, S.Farley, M.V.Umansky, X.Q.Xu * * Contact: Ben Dudson, bd512@york.ac.uk - * + * * This file is part of BOUT++. * * BOUT++ is free software: you can redistribute it and/or modify @@ -107,7 +107,7 @@ const Field3D smooth_y(const Field3D& f) { Issues ====== - + Assumes every processor has the same domain shape Will only work if X communicator is constant in Y @@ -162,14 +162,14 @@ const Field2D averageX(const Field2D& f) { ====== Creates static arrays - + Not thread safe - + Assumes every processor has the same domain shape - + Will only work if X communicator is constant in Y so no processor/branch cuts in X - + */ const Field3D averageX(const Field3D& f) { Mesh* mesh = f.getMesh(); @@ -349,7 +349,7 @@ BoutReal Vol_Integral([[maybe_unused]] 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 aab75b8f19..dc2077192d 100644 --- a/src/sys/derivs.cxx +++ b/src/sys/derivs.cxx @@ -69,7 +69,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, @@ -82,7 +82,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), @@ -100,21 +100,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; } @@ -151,12 +151,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())) @@ -170,12 +171,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; @@ -188,12 +190,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())) @@ -207,11 +210,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; @@ -222,13 +226,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()); } /******************************************************************************* @@ -238,37 +242,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())); } /******************************************************************************* @@ -386,14 +390,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 ///////////////// @@ -402,14 +406,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 ///////////////// @@ -418,7 +422,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 @@ -428,7 +432,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(); @@ -441,7 +445,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(); } /******************************************************************************* @@ -450,13 +454,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(); } ///////////////////////////////////////////////////////////////////////// @@ -464,13 +468,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(); } ///////////////////////////////////////////////////////////////////////// @@ -478,11 +482,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 214c022cd5..5bb87231e8 100644 --- a/tests/MMS/laplace/laplace.cxx +++ b/tests/MMS/laplace/laplace.cxx @@ -26,8 +26,8 @@ int main(int argc, char** argv) { meshoptions->get("Lx", Lx, 1.0); /*this assumes equidistant grid*/ - mesh->getCoordinates()->dx = Lx / (mesh->GlobalNx - 2 * mesh->xstart); - mesh->getCoordinates()->dz = TWOPI * Lx / (mesh->GlobalNz - 2 * mesh->zstart); + mesh->getCoordinates()->setDx(Lx / (mesh->GlobalNx - 2 * mesh->xstart)); + mesh->getCoordinates()->setDz(TWOPI * Lx / (mesh->GlobalNz - 2 * mesh->zstart)); ///// // 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/spatial/fci/fci_mms.cxx b/tests/MMS/spatial/fci/fci_mms.cxx index 7967452f3d..dd77f38e92 100644 --- a/tests/MMS/spatial/fci/fci_mms.cxx +++ b/tests/MMS/spatial/fci/fci_mms.cxx @@ -49,7 +49,7 @@ int main(int argc, char** argv) { if constexpr (bout::build::use_metric_3d) { // Div_par operators require B parallel slices: // Coordinates::geometry doesn't ensure this (yet) - auto& Bxy = mesh->getCoordinates()->Bxy; + auto& Bxy = mesh->getCoordinates()->Bxy(); mesh->communicate(Bxy); } mesh->communicate(input, K); 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 7c284290b3..1ae5ded0da 100644 --- a/tests/integrated/test-laplacexy-short/test-laplacexy.cxx +++ b/tests/integrated/test-laplacexy-short/test-laplacexy.cxx @@ -74,8 +74,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); @@ -92,7 +92,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 543274d37d..3e215def58 100644 --- a/tests/integrated/test-laplacexy/test-laplacexy.cxx +++ b/tests/integrated/test-laplacexy/test-laplacexy.cxx @@ -69,7 +69,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; } auto laplacexy = LaplaceXY::create(); @@ -89,7 +89,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-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 a3e128bfdc..b9f80a6ae0 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 e9af4e5b36..a4af049d14 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..0ef3dceb53 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,14 +209,18 @@ int main(int argc, char** argv) { // Change the mesh spacing and cell volume (Jdy) Coordinates* coord = Te.getCoordinates(); + auto dy_copy = coord->dy(); + auto J_copy = coord->J(); 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); + 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_copy(x, y) = 1. - 0.9 * y_n; + J_copy(x, y) = 1. + y_n * y_n; } } + coord->setDy(dy_copy); + coord->setJ(J_copy); HeatFluxSNB snb; @@ -226,10 +232,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 +248,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 09aeeed0ea..9660fe7b10 100644 --- a/tests/unit/bout_test_main.cxx +++ b/tests/unit/bout_test_main.cxx @@ -22,6 +22,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"); // We throw and catch a bunch of exceptions as part of running the tests, and // the backtrace generation can _significantly_ slow them down diff --git a/tests/unit/fake_mesh.hxx b/tests/unit/fake_mesh.hxx index 6dbbd6200b..e142f57f74 100644 --- a/tests/unit/fake_mesh.hxx +++ b/tests/unit/fake_mesh.hxx @@ -84,6 +84,7 @@ public: options = Options::getRoot(); mpi = &mpi_in; } + FakeMesh(int nx, int ny, int nz) : FakeMesh(nx, ny, nz, *bout::globals::mpi) {} void setCoordinates(std::shared_ptr coords, @@ -102,14 +103,17 @@ public: } comm_handle send(FieldGroup& UNUSED(g)) override { return nullptr; } + comm_handle sendX(FieldGroup& UNUSED(g), comm_handle UNUSED(handle) = nullptr, bool UNUSED(disable_corners) = false) override { return nullptr; } + comm_handle sendY(FieldGroup& UNUSED(g), comm_handle UNUSED(handle) = nullptr) override { return nullptr; } + int wait(comm_handle UNUSED(handle)) override { return 0; } int getNXPE() const override { return 1; } int getNYPE() const override { return 1; } @@ -122,22 +126,29 @@ public: return 0; } bool firstX() const override { return true; } + bool lastX() const override { return true; } + int sendXOut(BoutReal* UNUSED(buffer), int UNUSED(size), int UNUSED(tag)) override { return 0; } + int sendXIn(BoutReal* UNUSED(buffer), int UNUSED(size), int UNUSED(tag)) override { return 0; } + comm_handle irecvXOut(BoutReal* UNUSED(buffer), int UNUSED(size), int UNUSED(tag)) override { return nullptr; } + comm_handle irecvXIn(BoutReal* UNUSED(buffer), int UNUSED(size), int UNUSED(tag)) override { return nullptr; } + MPI_Comm getXcomm(int UNUSED(jy)) const override { return BoutComm::get(); } + MPI_Comm getYcomm(int UNUSED(jx)) const override { return BoutComm::get(); } MPI_Comm getXZcomm() const override { return BoutComm::get(); } @@ -149,49 +160,72 @@ public: return jx < ix_separatrix; } int numberOfYBoundaries() const override { return 1; } + std::pair hasBranchCutLower(int UNUSED(jx)) const override { return std::make_pair(false, 0.); } + std::pair hasBranchCutUpper(int UNUSED(jx)) const override { return std::make_pair(false, 0.); } + bool firstY() const override { return true; } + bool lastY() const override { return true; } + bool firstY(int UNUSED(xpos)) const override { return true; } + bool lastY(int UNUSED(xpos)) const override { return true; } + RangeIterator iterateBndryLowerY() const override { return RangeIterator(xstart, xend); } + RangeIterator iterateBndryUpperY() const override { return RangeIterator(xstart, xend); } + RangeIterator iterateBndryLowerOuterY() const override { return RangeIterator(); } + RangeIterator iterateBndryLowerInnerY() const override { return RangeIterator(); } + RangeIterator iterateBndryUpperOuterY() const override { return RangeIterator(); } + RangeIterator iterateBndryUpperInnerY() const override { return RangeIterator(); } bool hasBndryLowerY() const override { return false; } bool hasBndryUpperY() const override { return false; } void addBoundary(BoundaryRegion* region) override { boundaries.push_back(region); } + std::vector getBoundaries() override { return boundaries; } + std::vector> getBoundariesPar(BoundaryParType UNUSED(type)) override { return std::vector>(); } + BoutReal GlobalX(int jx) const override { return jx; } + BoutReal GlobalY(int jy) const override { return jy; } BoutReal GlobalZ(int jz) const override { return jz; } BoutReal GlobalX(BoutReal jx) const override { return jx; } + BoutReal GlobalY(BoutReal jy) const override { return jy; } BoutReal GlobalZ(BoutReal jz) const override { return jz; } int getGlobalXIndex(int) const override { return 0; } + int getGlobalXIndexNoBoundaries(int) const override { return 0; } + int getGlobalYIndex(int y) const override { return y; } + int getGlobalYIndexNoBoundaries(int y) const override { return y; } int getGlobalZIndex(int z) const override { return z; } int getGlobalZIndexNoBoundaries(int z) const override { return z; } int getLocalXIndex(int) const override { return 0; } + int getLocalXIndexNoBoundaries(int) const override { return 0; } + int getLocalYIndex(int y) const override { return y; } + int getLocalYIndexNoBoundaries(int y) const override { return y; } int getLocalZIndex(int z) const override { return z; } int getLocalZIndexNoBoundaries(int z) const override { return z; } @@ -274,13 +308,14 @@ private: class FakeGridDataSource : public GridDataSource { public: FakeGridDataSource() {} + /// Constructor setting values which can be fetched from this source FakeGridDataSource(const Options& values) : values(values.copy()) {} /// 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 { @@ -291,6 +326,7 @@ public: sval = def; return false; } + bool get([[maybe_unused]] Mesh* m, int& ival, const std::string& name, int def = 0) override { if (values[name].isSet()) { @@ -300,6 +336,7 @@ public: ival = def; return false; } + bool get([[maybe_unused]] Mesh* m, BoutReal& rval, const std::string& name, BoutReal def = 0.0) override { if (values[name].isSet()) { @@ -309,6 +346,7 @@ public: rval = def; return false; } + bool get(Mesh* mesh, Field2D& fval, const std::string& name, BoutReal def = 0.0, CELL_LOC UNUSED(location) = CELL_DEFAULT) override { if (values[name].isSet()) { @@ -318,6 +356,7 @@ public: fval = def; return false; } + bool get(Mesh* mesh, Field3D& fval, const std::string& name, BoutReal def = 0.0, CELL_LOC UNUSED(location) = CELL_DEFAULT) override { if (values[name].isSet()) { @@ -327,6 +366,7 @@ public: fval = def; return false; } + bool get(Mesh* mesh, FieldPerp& fval, const std::string& name, BoutReal def = 0.0, CELL_LOC UNUSED(location) = CELL_DEFAULT) override { if (values[name].isSet()) { @@ -343,6 +383,7 @@ public: throw BoutException("Not Implemented"); return false; } + bool get([[maybe_unused]] Mesh* m, [[maybe_unused]] std::vector& var, [[maybe_unused]] const std::string& name, [[maybe_unused]] int len, [[maybe_unused]] int def = 0, diff --git a/tests/unit/fake_mesh_fixture.hxx b/tests/unit/fake_mesh_fixture.hxx index 2758dbe416..1fe622896b 100644 --- a/tests/unit/fake_mesh_fixture.hxx +++ b/tests/unit/fake_mesh_fixture.hxx @@ -34,85 +34,98 @@ template class FakeMeshFixture_tmpl : public ::testing::Test { public: - FakeMeshFixture_tmpl() - : mesh_m(NX, NY, NZ, mpi), mesh_staggered_m(NX, NY, NZ, mpi), - mesh_staggered(&mesh_staggered_m) { + FakeMeshFixture_tmpl() : mesh_m(NX, NY, NZ, mpi), mesh_staggered_m(NX, NY, NZ, mpi) { - bout::globals::mpi = &mpi; - bout::globals::mesh = &mesh_m; + delete bout::globals::mesh; + bout::globals::mpi = new MpiWrapper(); + bout::globals::mesh = new FakeMesh(nx, ny, nz); bout::globals::mesh->createDefaultRegions(); - mesh_m.setCoordinates(nullptr); + static_cast(bout::globals::mesh)->setCoordinates(nullptr); test_coords = std::make_shared( bout::globals::mesh, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.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}); - - // 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; + static_cast(bout::globals::mesh)->setCoordinates(test_coords); // 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 - mesh_m.setCoordinates(test_coords); - mesh_m.setGridDataSource(new FakeGridDataSource()); + static_cast(bout::globals::mesh)->setCoordinates(test_coords); + static_cast(bout::globals::mesh) + ->setGridDataSource(new FakeGridDataSource()); // May need a ParallelTransform to create fields, because create3D calls // fromFieldAligned test_coords->setParallelTransform( bout::utils::make_unique(*bout::globals::mesh)); - mesh_m.createBoundaryRegions(); + dynamic_cast(bout::globals::mesh)->createBoundaryRegions(); - mesh_staggered_m.StaggerGrids = true; - mesh_staggered_m.setCoordinates(nullptr); - mesh_staggered_m.setCoordinates(nullptr, CELL_XLOW); - mesh_staggered_m.setCoordinates(nullptr, CELL_YLOW); - mesh_staggered_m.setCoordinates(nullptr, CELL_ZLOW); - mesh_staggered_m.createDefaultRegions(); + delete mesh_staggered; + mesh_staggered = new FakeMesh(nx, ny, nz); + mesh_staggered->StaggerGrids = true; + dynamic_cast(mesh_staggered)->setCoordinates(nullptr); + dynamic_cast(mesh_staggered)->setCoordinates(nullptr, CELL_XLOW); + dynamic_cast(mesh_staggered)->setCoordinates(nullptr, CELL_YLOW); + dynamic_cast(mesh_staggered)->setCoordinates(nullptr, CELL_ZLOW); + mesh_staggered->createDefaultRegions(); test_coords_staggered = std::make_shared( - &mesh_staggered_m, Field2D{1.0, &mesh_staggered_m}, - Field2D{1.0, &mesh_staggered_m}, Field2D{1.0, &mesh_staggered_m}, - Field2D{1.0, &mesh_staggered_m}, Field2D{1.0, &mesh_staggered_m}, - Field2D{1.0, &mesh_staggered_m}, Field2D{1.0, &mesh_staggered_m}, - Field2D{1.0, &mesh_staggered_m}, Field2D{0.0, &mesh_staggered_m}, - Field2D{0.0, &mesh_staggered_m}, Field2D{0.0, &mesh_staggered_m}, - Field2D{1.0, &mesh_staggered_m}, Field2D{1.0, &mesh_staggered_m}, - Field2D{1.0, &mesh_staggered_m}, Field2D{0.0, &mesh_staggered_m}, - Field2D{0.0, &mesh_staggered_m}, Field2D{0.0, &mesh_staggered_m}, - Field2D{0.0, &mesh_staggered_m}, Field2D{0.0, &mesh_staggered_m}); - - // Set some auxilliary variables - test_coords_staggered->G1 = test_coords_staggered->G2 = test_coords_staggered->G3 = - 0.1; + mesh_staggered, Field2D{1.0, mesh_staggered}, Field2D{1.0, mesh_staggered}, + Field2D{1.0, mesh_staggered}, Field2D{1.0, mesh_staggered}, + Field2D{1.0, mesh_staggered}, Field2D{1.0, mesh_staggered}, + Field2D{1.0, mesh_staggered}, Field2D{1.0, mesh_staggered}, + Field2D{0.0, mesh_staggered}, Field2D{0.0, mesh_staggered}, + Field2D{0.0, mesh_staggered}, Field2D{1.0, mesh_staggered}, + Field2D{1.0, mesh_staggered}, Field2D{1.0, mesh_staggered}, + Field2D{0.0, mesh_staggered}, Field2D{0.0, mesh_staggered}, + Field2D{0.0, mesh_staggered}, Field2D{0.0, mesh_staggered}, + Field2D{0.0, mesh_staggered}); + static_cast(mesh_staggered)->setCoordinates(test_coords_staggered); // 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_m)); + bout::utils::make_unique(*mesh_staggered)); // Set all coordinates to the same Coordinates object for now - mesh_staggered_m.setCoordinates(test_coords_staggered); - mesh_staggered_m.setCoordinates(test_coords_staggered, CELL_XLOW); - mesh_staggered_m.setCoordinates(test_coords_staggered, CELL_YLOW); - mesh_staggered_m.setCoordinates(test_coords_staggered, CELL_ZLOW); + dynamic_cast(mesh_staggered)->setCoordinates(test_coords_staggered); + dynamic_cast(mesh_staggered) + ->setCoordinates(test_coords_staggered, CELL_XLOW); + dynamic_cast(mesh_staggered) + ->setCoordinates(test_coords_staggered, CELL_YLOW); + dynamic_cast(mesh_staggered) + ->setCoordinates(test_coords_staggered, CELL_ZLOW); } FakeMeshFixture_tmpl(const FakeMeshFixture_tmpl&) = delete; @@ -122,6 +135,9 @@ public: ~FakeMeshFixture_tmpl() override { bout::globals::mesh = nullptr; + delete mesh_staggered; + mesh_staggered = nullptr; + delete bout::globals::mpi; bout::globals::mpi = nullptr; Options::cleanup(); diff --git a/tests/unit/fake_parallel_mesh.hxx b/tests/unit/fake_parallel_mesh.hxx index b3e57c4968..992228175e 100644 --- a/tests/unit/fake_parallel_mesh.hxx +++ b/tests/unit/fake_parallel_mesh.hxx @@ -263,7 +263,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 b45206b979..fd7d1213a4 100644 --- a/tests/unit/field/test_field_factory.cxx +++ b/tests/unit/field/test_field_factory.cxx @@ -553,7 +553,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 674817abd2..6e10f4ba7a 100644 --- a/tests/unit/field/test_vector2d.cxx +++ b/tests/unit/field/test_vector2d.cxx @@ -47,7 +47,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 d8e9366574..6858948814 100644 --- a/tests/unit/field/test_vector3d.cxx +++ b/tests/unit/field/test_vector3d.cxx @@ -44,7 +44,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 0e9f597eae..9b1d0a15f8 100644 --- a/tests/unit/include/bout/test_petsc_indexer.cxx +++ b/tests/unit/include/bout/test_petsc_indexer.cxx @@ -45,7 +45,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 a0d99f66c9..070e3449be 100644 --- a/tests/unit/invert/laplace/test_laplace_cyclic.cxx +++ b/tests/unit/invert/laplace/test_laplace_cyclic.cxx @@ -35,8 +35,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; } @@ -48,7 +48,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()]); } @@ -56,7 +56,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]); } @@ -80,7 +80,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 3b1bbc5d39..6df42cddd1 100644 --- a/tests/unit/invert/laplace/test_laplace_hypre3d.cxx +++ b/tests/unit/invert/laplace/test_laplace_hypre3d.cxx @@ -40,7 +40,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; @@ -56,7 +56,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()]); } @@ -64,7 +64,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]); } @@ -72,7 +72,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()]); } @@ -80,7 +80,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]); } @@ -98,7 +98,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 157ec22c84..0844588e92 100644 --- a/tests/unit/invert/laplace/test_laplace_petsc3damg.cxx +++ b/tests/unit/invert/laplace/test_laplace_petsc3damg.cxx @@ -40,7 +40,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; @@ -56,7 +56,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()]); } @@ -64,7 +64,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]); } @@ -72,7 +72,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()]); } @@ -80,7 +80,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]); } @@ -99,7 +99,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 41dd40fcc3..0776acef9b 100644 --- a/tests/unit/mesh/data/test_gridfromoptions.cxx +++ b/tests/unit/mesh/data/test_gridfromoptions.cxx @@ -360,12 +360,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) @@ -374,12 +374,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. @@ -394,7 +394,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()) + 3; }, @@ -403,16 +403,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) { @@ -435,7 +435,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()) + 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()) + 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()) + 3; }, @@ -525,18 +525,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 } @@ -547,11 +547,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 579e6fdd7b..30839bf393 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -44,7 +44,6 @@ 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( diff --git a/tests/unit/mesh/test_coordinates.cxx b/tests/unit/mesh/test_coordinates.cxx index fb400e593e..7c51c70321 100644 --- a/tests/unit/mesh/test_coordinates.cxx +++ b/tests/unit/mesh/test_coordinates.cxx @@ -42,7 +42,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)); } @@ -75,7 +74,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)); } @@ -102,12 +100,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 @@ -133,16 +130,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 - coords.calcCovariant(); + 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) { @@ -166,35 +163,34 @@ TEST_F(CoordinatesTest, CalcCovariant) { FieldMetric{0.0}, // g_23 FieldMetric{0.0}, // ShiftTorsion FieldMetric{0.0}}; // IntShiftTorsion - // No call to Coordinates::geometry() needed here - coords.calcContravariant(); + 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 TEST_F(CoordinatesTest, DefaultConstructor) { Coordinates coords(mesh); - 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) { @@ -204,27 +200,28 @@ TEST_F(CoordinatesTest, ConstructWithMeshSpacing) { Coordinates coords(mesh); - 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}})); - Coordinates coords(mesh); - EXPECT_THROW(coords.geometry(), BoutException); + WithQuietOutput quiet_info{output_info}; + WithQuietOutput quiet_warn{output_warn}; + EXPECT_THROW(Coordinates{mesh}, BoutException); } TEST_F(CoordinatesTest, ConstructWithDiagonalContravariantMetric) { @@ -236,26 +233,26 @@ TEST_F(CoordinatesTest, ConstructWithDiagonalContravariantMetric) { Coordinates coords(mesh); // 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) { @@ -271,3 +268,282 @@ TEST_F(CoordinatesTest, NegativeB) { EXPECT_THROW(Coordinates coords(mesh), BoutException); } + +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 16985981bb..db9550799c 100644 --- a/tests/unit/mesh/test_coordinates_accessor.cxx +++ b/tests/unit/mesh/test_coordinates_accessor.cxx @@ -76,13 +76,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()); @@ -116,13 +124,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()); @@ -158,13 +174,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 d14d54964e..c94be9e5fc 100644 --- a/tests/unit/mesh/test_interpolation.cxx +++ b/tests/unit/mesh/test_interpolation.cxx @@ -70,7 +70,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)); } @@ -317,7 +316,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/tools/pylib/_boutpp_build/boutcpp.pxd.jinja b/tools/pylib/_boutpp_build/boutcpp.pxd.jinja index 9de826384b..e90777ad3f 100644 --- a/tools/pylib/_boutpp_build/boutcpp.pxd.jinja +++ b/tools/pylib/_boutpp_build/boutcpp.pxd.jinja @@ -79,10 +79,6 @@ cdef extern from "bout/coordinates.hxx": {{ metric_field }} G1, G2, G3 {{ metric_field }} ShiftTorsion {{ metric_field }} IntShiftTorsion - int geometry() except +raise_bout_py_error - int calcCovariant() except +raise_bout_py_error - int calcContravariant() except +raise_bout_py_error - int jacobian() except +raise_bout_py_error 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 587aa7d6a5..41b4479fc0 100644 --- a/tools/pylib/_boutpp_build/boutpp.pyx.jinja +++ b/tools/pylib/_boutpp_build/boutpp.pyx.jinja @@ -793,7 +793,7 @@ cdef options 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 ---------- @@ -856,6 +856,7 @@ cdef Mesh meshFromPtr(c.Mesh * obj): cdef Coordinates coordsFromPtr(c.Coordinates * obj): coords = Coordinates() coords.cobj = obj + coords._setmembers() return coords @@ -874,10 +875,6 @@ cdef public {{ metric_field }} IntShiftTorsion {% endset %} {{ class("Coordinates", comment="Contains information about geometry, such as metric tensors", data=data, defaultSO=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 %} {{ class("Laplacian", comment=""" Laplacian inversion solver 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); }