diff --git a/CHANGELOG.md b/CHANGELOG.md index 41e3e2c47b..a0cbfd5915 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ # Changelog +## [v6.0.0](https://github.com/boutproject/BOUT-dev/tree/v6.0.0 + +[Full Changelog](https://github.com/boutproject/BOUT-dev/compare/v5.2.0...) + +### Breaking changes + +- `Coordinates` has been refactored to with a more encapsulated interface. This + allows us to ensure that derived quantities are correctly updated when the + metric components are changed, as well as defer creation of the Christoffel + symbols, and other derivatives of the metric components. This change will + require most physics models to be updated. You can do this with the + `bout-upgrader` from `boutdata`: + ```console + $ bout-upgrader v6 v6_upgrader file/to/update.cxx + ```` + ## [v5.2.0](https://github.com/boutproject/BOUT-dev/tree/v5.2.0 [Full Changelog](https://github.com/boutproject/BOUT-dev/compare/v5.1.1...v5.2.0) diff --git a/CMakeLists.txt b/CMakeLists.txt index e6e424b55c..689c668264 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -116,10 +116,11 @@ set(BOUT_SOURCES ./include/bout/bout.hxx ./include/bout/bout_enum_class.hxx ./include/bout/bout_types.hxx - ./include/bout/build_config.hxx ./include/bout/boutcomm.hxx ./include/bout/boutexception.hxx + ./include/bout/build_config.hxx ./include/bout/caliper_wrapper.hxx + ./include/bout/christoffel_symbols.hxx ./include/bout/constants.hxx ./include/bout/coordinates.hxx ./include/bout/coordinates_accessor.hxx @@ -136,18 +137,21 @@ set(BOUT_SOURCES ./include/bout/field_accessor.hxx ./include/bout/field_data.hxx ./include/bout/field_factory.hxx - ./include/bout/fieldops.hxx ./include/bout/fieldgroup.hxx + ./include/bout/fieldops.hxx ./include/bout/fieldperp.hxx ./include/bout/fv_ops.hxx ./include/bout/fv_ops_impl.hxx + ./include/bout/g_values.hxx ./include/bout/generic_factory.hxx + ./include/bout/git_metadata.hxx ./include/bout/globalfield.hxx ./include/bout/globalindexer.hxx ./include/bout/globals.hxx ./include/bout/griddata.hxx ./include/bout/gyro_average.hxx ./include/bout/hypre_interface.hxx + ./include/bout/hyprelib.hxx ./include/bout/index_derivs.hxx ./include/bout/index_derivs_interface.hxx ./include/bout/initialprofiles.hxx @@ -164,6 +168,7 @@ set(BOUT_SOURCES ./include/bout/macro_for_each.hxx ./include/bout/mask.hxx ./include/bout/mesh.hxx + ./include/bout/metric_tensor.hxx ./include/bout/monitor.hxx ./include/bout/mpi_wrapper.hxx ./include/bout/msg_stack.hxx @@ -216,8 +221,8 @@ set(BOUT_SOURCES ./include/bout/vector2d.hxx ./include/bout/vector3d.hxx ./include/bout/where.hxx - ./src/bout++.cxx ./src/bout++-time.hxx + ./src/bout++.cxx ./src/field/field.cxx ./src/field/field2d.cxx ./src/field/field3d.cxx @@ -240,6 +245,8 @@ set(BOUT_SOURCES ./src/invert/laplace/common_transform.hxx ./src/invert/laplace/impls/cyclic/cyclic_laplace.cxx ./src/invert/laplace/impls/cyclic/cyclic_laplace.hxx + ./src/invert/laplace/impls/hypre3d/hypre3d_laplace.cxx + ./src/invert/laplace/impls/hypre3d/hypre3d_laplace.hxx ./src/invert/laplace/impls/iterative_parallel_tri/iterative_parallel_tri.cxx ./src/invert/laplace/impls/iterative_parallel_tri/iterative_parallel_tri.hxx ./src/invert/laplace/impls/multigrid/multigrid_alg.cxx @@ -262,8 +269,6 @@ set(BOUT_SOURCES ./src/invert/laplace/impls/serial_tri/serial_tri.hxx ./src/invert/laplace/impls/spt/spt.cxx ./src/invert/laplace/impls/spt/spt.hxx - ./src/invert/laplace/impls/hypre3d/hypre3d_laplace.cxx - ./src/invert/laplace/impls/hypre3d/hypre3d_laplace.hxx ./src/invert/laplace/invert_laplace.cxx ./src/invert/laplacexy/impls/hypre/laplacexy-hypre.cxx ./src/invert/laplacexy/impls/hypre/laplacexy-hypre.hxx @@ -286,23 +291,26 @@ set(BOUT_SOURCES ./src/mesh/boundary_factory.cxx ./src/mesh/boundary_region.cxx ./src/mesh/boundary_standard.cxx + ./src/mesh/christoffel_symbols.cxx ./src/mesh/coordinates.cxx ./src/mesh/coordinates_accessor.cxx ./src/mesh/data/gridfromfile.cxx ./src/mesh/data/gridfromoptions.cxx ./src/mesh/difops.cxx ./src/mesh/fv_ops.cxx + ./src/mesh/g_values.cxx ./src/mesh/impls/bout/boutmesh.cxx ./src/mesh/impls/bout/boutmesh.hxx ./src/mesh/index_derivs.cxx - ./src/mesh/interpolation_xz.cxx ./src/mesh/interpolation/bilinear_xz.cxx ./src/mesh/interpolation/hermite_spline_xz.cxx ./src/mesh/interpolation/hermite_spline_z.cxx ./src/mesh/interpolation/interpolation_z.cxx ./src/mesh/interpolation/lagrange_4pt_xz.cxx + ./src/mesh/interpolation_xz.cxx ./src/mesh/invert3x3.hxx ./src/mesh/mesh.cxx + ./src/mesh/metric_tensor.cxx ./src/mesh/parallel/fci.cxx ./src/mesh/parallel/fci.hxx ./src/mesh/parallel/fci_comm.cxx @@ -369,18 +377,17 @@ set(BOUT_SOURCES ./src/sys/derivs.cxx ./src/sys/expressionparser.cxx ./src/sys/generator_context.cxx - ./include/bout/hyprelib.hxx ./src/sys/hyprelib.cxx ./src/sys/msg_stack.cxx ./src/sys/options.cxx ./src/sys/options/optionparser.hxx + ./src/sys/options/options_adios.cxx + ./src/sys/options/options_adios.hxx ./src/sys/options/options_ini.cxx ./src/sys/options/options_ini.hxx ./src/sys/options/options_io.cxx ./src/sys/options/options_netcdf.cxx ./src/sys/options/options_netcdf.hxx - ./src/sys/options/options_adios.cxx - ./src/sys/options/options_adios.hxx ./src/sys/optionsreader.cxx ./src/sys/output.cxx ./src/sys/output_bout_types.cxx @@ -390,7 +397,6 @@ set(BOUT_SOURCES ./src/sys/timer.cxx ./src/sys/type_name.cxx ./src/sys/utils.cxx - ./include/bout/git_metadata.hxx ${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 7208d89ddf..1ffa925580 100644 --- a/examples/6field-simple/elm_6f.cxx +++ b/examples/6field-simple/elm_6f.cxx @@ -6,19 +6,32 @@ * T. Xia *******************************************************************************/ +#include "bout/assert.hxx" #include "bout/bout.hxx" +#include "bout/bout_types.hxx" +#include "bout/build_defines.hxx" #include "bout/constants.hxx" +#include "bout/coordinates.hxx" #include "bout/derivs.hxx" +#include "bout/difops.hxx" +#include "bout/field2d.hxx" +#include "bout/field3d.hxx" +#include "bout/fieldgroup.hxx" #include "bout/initialprofiles.hxx" #include "bout/interpolation_xz.hxx" #include "bout/invert_laplace.hxx" -#include "bout/invert_parderiv.hxx" #include "bout/msg_stack.hxx" +#include "bout/output.hxx" #include "bout/physicsmodel.hxx" +#include "bout/smoothing.hxx" #include "bout/sourcex.hxx" #include "bout/tokamak_coordinates.hxx" +#include "bout/unused.hxx" +#include "bout/vecops.hxx" +#include "bout/where.hxx" #include +#include constexpr BoutReal eV_K = 11605.0; // 1eV = 11605K @@ -356,7 +369,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); @@ -696,7 +709,7 @@ class Elm_6f : public PhysicsModel { if (mesh->IncIntShear) { // BOUT-06 style, using d/dx = d/dpsi + I * d/dz - mesh->getCoordinates()->IntShiftTorsion = I; + mesh->getCoordinates()->setIntShiftTorsion(I); } else { // Dimits style, using local coordinate system if (include_curvature) { @@ -929,7 +942,7 @@ class Elm_6f : public PhysicsModel { output.write("\tlog Lambda: {:e}\n", LnLambda); nu_e = 2.91e-6 * LnLambda * ((N0)*Nbar * density / 1.e6) - * pow(Te0 * Tebar, -1.5); // nu_e in 1/S. + * pow(Field2D{Te0 * Tebar}, -1.5); // nu_e in 1/S. output.write("\telectron collision rate: {:e} -> {:e} [1/s]\n", min(nu_e), max(nu_e)); // nu_e.applyBoundary(); // mesh->communicate(nu_e); @@ -941,7 +954,8 @@ class Elm_6f : public PhysicsModel { // xqx addition, begin // Use Spitzer thermal conductivities nu_i = 4.80e-8 * (Zi * Zi * Zi * Zi / sqrt(AA)) * LnLambda - * ((N0)*Nbar * density / 1.e6) * pow(Ti0 * Tibar, -1.5); // nu_i in 1/S. + * ((N0)*Nbar * density / 1.e6) + * pow(Field2D{Ti0 * Tibar}, -1.5); // nu_i in 1/S. // output.write("\tCoulomb Logarithm: {:e} \n", max(LnLambda)); output.write("\tion collision rate: {:e} -> {:e} [1/s]\n", min(nu_i), max(nu_i)); @@ -1006,8 +1020,9 @@ class Elm_6f : public PhysicsModel { // Use Spitzer resistivity output.write("\n\tSpizter parameters"); // output.write("\tTemperature: {:e} -> {:e} [eV]\n", min(Te), max(Te)); - eta_spitzer = 0.51 * 1.03e-4 * Zi * LnLambda - * pow(Te0 * Tebar, -1.5); // eta in Ohm-m. NOTE: ln(Lambda) = 20 + eta_spitzer = + 0.51 * 1.03e-4 * Zi * LnLambda + * pow(Field2D{Te0 * Tebar}, -1.5); // eta in Ohm-m. NOTE: ln(Lambda) = 20 output.write("\tSpitzer resistivity: {:e} -> {:e} [Ohm m]\n", min(eta_spitzer), max(eta_spitzer)); eta_spitzer /= SI::mu0 * Va * Lbar; @@ -1114,7 +1129,7 @@ class Elm_6f : public PhysicsModel { // Only if not restarting: Check initial perturbation // Set U to zero where P0 < vacuum_pressure - U = where(P0 - vacuum_pressure, U, 0.0); + U = where(Field2D{P0 - vacuum_pressure}, U, 0.0); // Field2D lap_temp = 0.0; Field2D logn0 = laplace_alpha * N0; @@ -1241,24 +1256,25 @@ class Elm_6f : public PhysicsModel { // Update resistivity if (spitzer_resist) { // Use Spitzer formula - eta_spitzer = 0.51 * 1.03e-4 * Zi * LnLambda - * pow(Te_tmp * Tebar, -1.5); // eta in Ohm-m. ln(Lambda) = 20 + eta_spitzer = + 0.51 * 1.03e-4 * Zi * LnLambda + * pow(Field3D{Te_tmp * Tebar}, -1.5); // eta in Ohm-m. ln(Lambda) = 20 eta_spitzer /= SI::mu0 * Va * Lbar; } else { eta = core_resist + (vac_resist - core_resist) * vac_mask; } nu_e = 2.91e-6 * LnLambda * (N_tmp * Nbar * density / 1.e6) - * pow(Te_tmp * Tebar, -1.5); // nu_e in 1/S. + * pow(Field3D{Te_tmp * Tebar}, -1.5); // nu_e in 1/S. if (diffusion_par > 0.0) { // Use Spitzer thermal conductivities nu_i = 4.80e-8 * (Zi * Zi * Zi * Zi / sqrt(AA)) * LnLambda * (N_tmp * Nbar * density / 1.e6) - * pow(Ti_tmp * Tibar, -1.5); // nu_i in 1/S. - vth_i = 9.79e3 * sqrt(Ti_tmp * Tibar / AA); // vth_i in m/S. - vth_e = 4.19e5 * sqrt(Te_tmp * Tebar); // vth_e in m/S. + * pow(Field3D{Ti_tmp * Tibar}, -1.5); // nu_i in 1/S. + vth_i = 9.79e3 * sqrt(Ti_tmp * Tibar / AA); // vth_i in m/S. + vth_e = 4.19e5 * sqrt(Te_tmp * Tebar); // vth_e in m/S. } if (diffusion_par > 0.0) { @@ -1399,11 +1415,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..ddeb5ef9d4 100644 --- a/examples/IMEX/drift-wave-constraint/test-drift.cxx +++ b/examples/IMEX/drift-wave-constraint/test-drift.cxx @@ -61,10 +61,10 @@ class DriftWave : public PhysicsModel { // This code results in ddt(Ne) depending on y+2, y-2 // which are not (currently) included in the coloring // The result is that IMEX-BDF2 with coloring doesn't converge - + Ve = ( Grad_par(phi) - Grad_par(Ne) ) / nu; mesh->communicate(Ve); - + ddt(Ne) = -Div_par(Ve); ddt(Vort) = -Div_par(Ve); */ @@ -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 b302b5dfb3..c3cd40630c 100644 --- a/examples/conducting-wall-mode/cwm.cxx +++ b/examples/conducting-wall-mode/cwm.cxx @@ -5,14 +5,26 @@ * Model version in the code created by M. Umansky and J. Myra. *******************************************************************************/ +#include +#include #include +#include +#include +#include +#include #include #include #include +#include #include +#include #include +#include #include +#include +#include + class CWM : public PhysicsModel { private: // 2D initial profiles @@ -319,7 +331,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; } @@ -328,10 +340,10 @@ class CWM : public PhysicsModel { Field3D result; if (bout_exb) { // Use a subset of terms for comparison to BOUT-06 - result = VDDZ(-DDX(p), f); + result = VDDZ(Field2D{-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; } @@ -343,7 +355,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/elm-pb-outerloop/elm_pb_outerloop.cxx b/examples/elm-pb-outerloop/elm_pb_outerloop.cxx index dbad416281..54c3faf3e0 100644 --- a/examples/elm-pb-outerloop/elm_pb_outerloop.cxx +++ b/examples/elm-pb-outerloop/elm_pb_outerloop.cxx @@ -819,7 +819,7 @@ class ELMpb : public PhysicsModel { if (mesh->IncIntShear) { // BOUT-06 style, using d/dx = d/dpsi + I * d/dz - mesh->getCoordinates()->IntShiftTorsion = I; + mesh->getCoordinates()->setIntShiftTorsion(I); } else { // Dimits style, using local coordinate system if (include_curvature) { @@ -1749,11 +1749,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"); @@ -1865,7 +1865,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 62cc970869..e4bd1bbee3 100644 --- a/examples/elm-pb/elm_pb.cxx +++ b/examples/elm-pb/elm_pb.cxx @@ -775,7 +775,7 @@ class ELMpb : public PhysicsModel { if (mesh->IncIntShear) { // BOUT-06 style, using d/dx = d/dpsi + I * d/dz - mesh->getCoordinates()->IntShiftTorsion = I; + mesh->getCoordinates()->setIntShiftTorsion(I); } else { // Dimits style, using local coordinate system if (include_curvature) { @@ -1772,11 +1772,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"); @@ -1914,7 +1914,7 @@ class ELMpb : public PhysicsModel { BoutReal pnorm = P0(0, 0); ddt(P) += heating_P * source_expx2(P0, 2. * hp_width, 0.5 * hp_length) * (Tbar / pnorm); // heat source - ddt(P) += (100. * source_tanhx(P0, hp_width, hp_length) + 0.01) * metric->g11 + ddt(P) += (100. * source_tanhx(P0, hp_width, hp_length) + 0.01) * metric->g11() * D2DX2(P) * (Tbar / Lbar / Lbar); // radial diffusion } diff --git a/examples/fci-wave/fci-wave.cxx b/examples/fci-wave/fci-wave.cxx index 9f8bb18b8f..fd3adbe2ab 100644 --- a/examples/fci-wave/fci-wave.cxx +++ b/examples/fci-wave/fci-wave.cxx @@ -1,7 +1,8 @@ - #include "bout/parallel_boundary_region.hxx" #include "bout/physicsmodel.hxx" +#include + class FCIwave : public PhysicsModel { private: Field3D n, nv; //< Evolving density, momentum @@ -45,7 +46,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 f4347ca2b3..4e5e8538c3 100644 --- a/examples/gyro-gem/gem.cxx +++ b/examples/gyro-gem/gem.cxx @@ -363,7 +363,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.; @@ -1116,7 +1116,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); } //////////////////////////////////////////////////////////////////////// @@ -1131,7 +1131,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 ; } @@ -1147,8 +1147,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/include/bout/christoffel_symbols.hxx b/include/bout/christoffel_symbols.hxx new file mode 100644 index 0000000000..db88b8688e --- /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(const 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 2c33701762..f01e3883e0 100644 --- a/include/bout/coordinates.hxx +++ b/include/bout/coordinates.hxx @@ -30,30 +30,29 @@ #include "bout/field_data.hxx" #include #include +#include #include #include +#include +#include #include #include #include #include #include +#include +#include class Mesh; class YBoundary; /*! * 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 + using FieldMetric = bout::FieldMetric; /// Standard constructor from input Coordinates(Mesh* mesh, Options* options = nullptr); @@ -64,8 +63,8 @@ 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); + Coordinates(Mesh* mesh, Options* options, CELL_LOC loc, const Coordinates* coords_in, + 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), @@ -76,32 +75,81 @@ public: 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; - /// 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; - /// True if corrections for non-uniform mesh spacing should be included in operators - bool 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 BoutReal& zlength(int x, int y) const { return zlength()(x, y); } - FieldMetric J; ///< Coordinate system Jacobian, so volume of cell is J*dx*dy*dz + /// True if corrections for non-uniform mesh spacing should be included in operators + bool non_uniform() const { return non_uniform_; } + void setNon_uniform(bool non_uniform) { non_uniform_ = non_uniform; } - FieldMetric Bxy; ///< Magnitude of B = nabla z times nabla x + /// 2nd-order correction for non-uniform meshes d/di(1/dx), d/di(1/dy) and d/di(1/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_; } - /// Contravariant metric tensor (g^{ij}) - FieldMetric g11, g22, g33, g12, g13, g23; +#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 /// Covariant metric tensor - FieldMetric g_11, g_22, g_33, g_12, g_13, g_23; + 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(); } /// get g_22 at the cell faces; const FieldMetric& g_22_ylow() const; @@ -235,26 +283,116 @@ private: void _compute_cell_volume() const; public: - /// 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; + /// Contravariant metric tensor (g^{ij}) + 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 + 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); + } + +#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 not(BOUT_USE_METRIC_3D) + 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 - FieldMetric G1, G2, G3; + 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(); + + void communicateDz(); + + ///< Coordinate system Jacobian, so volume of cell is J*dx*dy*dz + const FieldMetric& J() const; + + ///< Magnitude of B = nabla z times nabla x + const FieldMetric& Bxy() const { return Bxy_; } + + void setJ(const FieldMetric& J, bool communicate = true); + + void setBxy(FieldMetric Bxy, 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 @@ -273,86 +411,53 @@ public: return *transform; } - /////////////////////////////////////////////////////////// - // Operators - /////////////////////////////////////////////////////////// + /// Christoffel symbol of the second kind (connection coefficients) + const FieldMetric& G1_11() const { return christoffel_symbols().G1_11(); } + const FieldMetric& G1_22() const { return christoffel_symbols().G1_22(); } + const FieldMetric& G1_33() const { return christoffel_symbols().G1_33(); } + const FieldMetric& G1_12() const { return christoffel_symbols().G1_12(); } + const FieldMetric& G1_13() const { return christoffel_symbols().G1_13(); } + const FieldMetric& G1_23() const { return christoffel_symbols().G1_23(); } + const FieldMetric& G2_11() const { return christoffel_symbols().G2_11(); } + const FieldMetric& G2_22() const { return christoffel_symbols().G2_22(); } + const FieldMetric& G2_33() const { return christoffel_symbols().G2_33(); } + const FieldMetric& G2_12() const { return christoffel_symbols().G2_12(); } + const FieldMetric& G2_13() const { return christoffel_symbols().G2_13(); } + const FieldMetric& G2_23() const { return christoffel_symbols().G2_23(); } + const FieldMetric& G3_11() const { return christoffel_symbols().G3_11(); } + const FieldMetric& G3_22() const { return christoffel_symbols().G3_22(); } + const FieldMetric& G3_33() const { return christoffel_symbols().G3_33(); } + const FieldMetric& G3_12() const { return christoffel_symbols().G3_12(); } + const FieldMetric& G3_13() const { return christoffel_symbols().G3_13(); } + const FieldMetric& G3_23() const { 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; + + const ChristoffelSymbols& christoffel_symbols() const; + + GValues& g_values() const; + + void recalculateAndReset(bool recalculate_staggered, + bool force_interpolate_from_centre); - FieldMetric DDX(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", - const std::string& region = "RGN_NOBNDRY"); - - FieldMetric DDY(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", - const std::string& region = "RGN_NOBNDRY") const; - - FieldMetric DDZ(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", - const std::string& region = "RGN_NOBNDRY"); - - Field3D DDX(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", - const std::string& region = "RGN_NOBNDRY"); - - Field3D DDY(const Field3DParallel& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", - const std::string& region = "RGN_NOBNDRY") const; - - Field3D DDZ(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", - const std::string& region = "RGN_NOBNDRY"); - - /// Gradient along magnetic field b.Grad(f) - FieldMetric Grad_par(const Field2D& var, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT"); - - Field3D Grad_par(const Field3DParallel& var, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT"); - - /// Advection along magnetic field V*b.Grad(f) - FieldMetric Vpar_Grad_par(const Field2D& v, const Field2D& f, - CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT"); - - Field3D Vpar_Grad_par(const Field3D& v, const Field3DParallel& f, - CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT"); - - /// Divergence along magnetic field Div(b*f) = B.Grad(f/B) - FieldMetric Div_par(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT"); - - Field3D Div_par(const Field3DParallel& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT"); - - // Second derivative along magnetic field - FieldMetric Grad2_par2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT"); - - Field3D Grad2_par2(const Field3DParallel& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT"); - // Perpendicular Laplacian operator, using only X-Z derivatives - // NOTE: This might be better bundled with the Laplacian inversion code - // since it makes use of the same coefficients and FFT routines - FieldMetric Delp2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, bool useFFT = true); - Field3D Delp2(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, bool useFFT = true); - FieldPerp Delp2(const FieldPerp& f, CELL_LOC outloc = CELL_DEFAULT, bool useFFT = true); - - // Full parallel Laplacian operator on scalar field - // Laplace_par(f) = Div( b (b dot Grad(f)) ) - FieldMetric Laplace_par(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT); - Field3D Laplace_par(const Field3DParallel& f, CELL_LOC outloc = CELL_DEFAULT); - - // Full Laplacian operator on scalar field - FieldMetric Laplace(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& dfdy_boundary_conditions = "free_o3", - const std::string& dfdy_dy_region = ""); - Field3D Laplace(const Field3DParallel& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& dfdy_boundary_conditions = "free_o3", - const std::string& dfdy_dy_region = ""); - - // Full perpendicular Laplacian, in form of inverse of Laplacian operator in LaplaceXY - // solver - Field2D Laplace_perpXY(const Field2D& A, const Field2D& f); + FieldMetric recalculateJacobian() const; friend std::shared_ptr getYBoundary(Coordinates* coords, YBndryType type); @@ -360,36 +465,82 @@ private: std::shared_ptr makeYBoundary(YBndryType type) const; int nz; // Size of mesh in Z. This is mesh->ngz-1 Mesh* localmesh; - Options* localoptions; + Options* localoptions{nullptr}; 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(); + void invalidateMetricCaches(); + void invalidateJacobianCaches(); + void invalidateCellGeometryCaches(); + void invalidateAccessorCache() const; mutable std::array, 3> ybndrys; + + 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); + /// Read quantities with given suffix from `Mesh` void readFromMesh(Options* options, const std::string& suffix); + + /// Read parallel slices of metric components from `Mesh` + void readParallelMetricComponents(); + +protected: + /// For testing purposes only; inherit and make this public + void splitBxyParallelSlices(); }; +namespace bout { +std::string parallelSliceFieldName(std::string_view field, int offset); +} + #endif // BOUT_COORDINATES_H diff --git a/include/bout/derivs.hxx b/include/bout/derivs.hxx index 14bc5c2824..8ee3b872a1 100644 --- a/include/bout/derivs.hxx +++ b/include/bout/derivs.hxx @@ -29,12 +29,14 @@ #ifndef BOUT_DERIVS_H #define BOUT_DERIVS_H +#include "bout/bout_types.hxx" #include "bout/field2d.hxx" #include "bout/field3d.hxx" +#include "bout/metric_tensor.hxx" #include "bout/vector2d.hxx" #include "bout/vector3d.hxx" -#include "bout/bout_types.hxx" +#include #include ////////// FIRST DERIVATIVES ////////// @@ -67,9 +69,9 @@ Field3D DDX(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -Coordinates::FieldMetric DDX(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", - const std::string& region = "RGN_NOBNDRY"); +bout::FieldMetric DDX(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", + const std::string& region = "RGN_NOBNDRY"); /// Calculate first partial derivative in Y /// @@ -106,9 +108,9 @@ DDY(const E& expr, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = " /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -Coordinates::FieldMetric DDY(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", - const std::string& region = "RGN_NOBNDRY"); +bout::FieldMetric DDY(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", + const std::string& region = "RGN_NOBNDRY"); /// Calculate first partial derivative in Z /// @@ -138,9 +140,9 @@ Field3D DDZ(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -Coordinates::FieldMetric DDZ(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", - const std::string& region = "RGN_NOBNDRY"); +bout::FieldMetric DDZ(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", + const std::string& region = "RGN_NOBNDRY"); /// Calculate first partial derivative in Z /// @@ -154,7 +156,7 @@ Coordinates::FieldMetric DDZ(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -Vector3D DDZ(const Vector3D& f, CELL_LOC outloc = CELL_DEFAULT, +Vector3D DDZ(const Vector3D& v, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); @@ -170,7 +172,7 @@ Vector3D DDZ(const Vector3D& f, CELL_LOC outloc = CELL_DEFAULT, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -Vector2D DDZ(const Vector2D& f, CELL_LOC outloc = CELL_DEFAULT, +Vector2D DDZ(const Vector2D& v, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); @@ -204,9 +206,9 @@ Field3D D2DX2(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -Coordinates::FieldMetric D2DX2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", - const std::string& region = "RGN_NOBNDRY"); +bout::FieldMetric D2DX2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", + const std::string& region = "RGN_NOBNDRY"); /// Calculate second partial derivative in Y /// @@ -236,9 +238,9 @@ Field3D D2DY2(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -Coordinates::FieldMetric D2DY2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", - const std::string& region = "RGN_NOBNDRY"); +bout::FieldMetric D2DY2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", + const std::string& region = "RGN_NOBNDRY"); /// Calculate second partial derivative in Z /// @@ -268,9 +270,9 @@ Field3D D2DZ2(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -Coordinates::FieldMetric D2DZ2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", - const std::string& region = "RGN_NOBNDRY"); +bout::FieldMetric D2DZ2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", + const std::string& region = "RGN_NOBNDRY"); ////////// FOURTH DERIVATIVES ////////// @@ -302,9 +304,9 @@ Field3D D4DX4(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -Coordinates::FieldMetric D4DX4(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", - const std::string& region = "RGN_NOBNDRY"); +bout::FieldMetric D4DX4(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", + const std::string& region = "RGN_NOBNDRY"); /// Calculate forth partial derivative in Y /// @@ -334,9 +336,9 @@ Field3D D4DY4(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -Coordinates::FieldMetric D4DY4(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", - const std::string& region = "RGN_NOBNDRY"); +bout::FieldMetric D4DY4(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", + const std::string& region = "RGN_NOBNDRY"); /// Calculate forth partial derivative in Z /// @@ -366,9 +368,9 @@ Field3D D4DZ4(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -Coordinates::FieldMetric D4DZ4(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", - const std::string& region = "RGN_NOBNDRY"); +bout::FieldMetric D4DZ4(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", + const std::string& region = "RGN_NOBNDRY"); /// For terms of form v * grad(f) /// @@ -400,10 +402,9 @@ Field3D VDDX(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -Coordinates::FieldMetric VDDX(const Field2D& v, const Field2D& f, - CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", - const std::string& region = "RGN_NOBNDRY"); +bout::FieldMetric VDDX(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", + const std::string& region = "RGN_NOBNDRY"); /// For terms of form v * grad(f) /// @@ -435,10 +436,9 @@ Field3D VDDY(const Field3D& v, const Field3DParallel& f, CELL_LOC outloc = CELL_ /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -Coordinates::FieldMetric VDDY(const Field2D& v, const Field2D& f, - CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", - const std::string& region = "RGN_NOBNDRY"); +bout::FieldMetric VDDY(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", + const std::string& region = "RGN_NOBNDRY"); /// For terms of form v * grad(f) /// @@ -470,10 +470,9 @@ Field3D VDDZ(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -Coordinates::FieldMetric VDDZ(const Field2D& v, const Field2D& f, - CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", - const std::string& region = "RGN_NOBNDRY"); +bout::FieldMetric VDDZ(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", + const std::string& region = "RGN_NOBNDRY"); /// For terms of form v * grad(f) /// @@ -488,10 +487,9 @@ Coordinates::FieldMetric VDDZ(const Field2D& v, const Field2D& f, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -Coordinates::FieldMetric VDDZ(const Field3D& v, const Field2D& f, - CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", - const std::string& region = "RGN_NOBNDRY"); +bout::FieldMetric VDDZ(const Field3D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", + const std::string& region = "RGN_NOBNDRY"); /// for terms of form div(v * f) /// @@ -523,10 +521,9 @@ Field3D FDDX(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -Coordinates::FieldMetric FDDX(const Field2D& v, const Field2D& f, - CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", - const std::string& region = "RGN_NOBNDRY"); +bout::FieldMetric FDDX(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", + const std::string& region = "RGN_NOBNDRY"); /// for terms of form div(v * f) /// @@ -558,10 +555,9 @@ Field3D FDDY(const Field3D& v, const Field3DParallel& f, CELL_LOC outloc = CELL_ /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -Coordinates::FieldMetric FDDY(const Field2D& v, const Field2D& f, - CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", - const std::string& region = "RGN_NOBNDRY"); +bout::FieldMetric FDDY(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", + const std::string& region = "RGN_NOBNDRY"); /// for terms of form div(v * f) /// @@ -593,10 +589,9 @@ Field3D FDDZ(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -Coordinates::FieldMetric FDDZ(const Field2D& v, const Field2D& f, - CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", - const std::string& region = "RGN_NOBNDRY"); +bout::FieldMetric FDDZ(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", + const std::string& region = "RGN_NOBNDRY"); /// Calculate mixed partial derivative in x and y /// @@ -639,11 +634,11 @@ Field3D D2DXDY(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, /// (default) then the same as the region for the calculation as a /// whole. If dfdy_region < region in size then this will cause /// errors. -Coordinates::FieldMetric D2DXDY(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", - const std::string& region = "RGN_NOBNDRY", - const std::string& dfdy_boundary_condition = "free_o3", - const std::string& dfdy_region = ""); +bout::FieldMetric D2DXDY(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", + const std::string& region = "RGN_NOBNDRY", + const std::string& dfdy_boundary_condition = "free_o3", + const std::string& dfdy_region = ""); /// Calculate mixed partial derivative in x and z /// @@ -673,9 +668,9 @@ Field3D D2DXDZ(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -Coordinates::FieldMetric D2DXDZ(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", - const std::string& region = "RGN_NOBNDRY"); +bout::FieldMetric D2DXDZ(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", + const std::string& region = "RGN_NOBNDRY"); /// Calculate mixed partial derivative in y and z /// @@ -705,8 +700,8 @@ Field3D D2DYDZ(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -Coordinates::FieldMetric D2DYDZ(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", - const std::string& region = "RGN_NOBNDRY"); +bout::FieldMetric D2DYDZ(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", + const std::string& region = "RGN_NOBNDRY"); #endif // BOUT_DERIVS_H diff --git a/include/bout/difops.hxx b/include/bout/difops.hxx index 28a4da9f51..fcde8a9b7c 100644 --- a/include/bout/difops.hxx +++ b/include/bout/difops.hxx @@ -36,11 +36,12 @@ #ifndef BOUT_DIFOPS_H #define BOUT_DIFOPS_H +#include "bout/bout_types.hxx" #include "bout/field2d.hxx" #include "bout/field3d.hxx" +#include "bout/metric_tensor.hxx" -#include "bout/bout_types.hxx" -#include "bout/coordinates.hxx" +#include class Solver; @@ -53,10 +54,10 @@ class Solver; * enabled) * @param[in] method The method to use. The default is set in the options. */ -Coordinates::FieldMetric Grad_par(const Field2D& var, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT"); -inline Coordinates::FieldMetric Grad_par(const Field2D& var, CELL_LOC outloc, - DIFF_METHOD method) { +bout::FieldMetric Grad_par(const Field2D& var, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT"); +inline bout::FieldMetric Grad_par(const Field2D& var, CELL_LOC outloc, + DIFF_METHOD method) { return Grad_par(var, outloc, toString(method)); } @@ -89,12 +90,12 @@ Field3D Grad_parP(const Field3D& apar, const Field3D& f); * @param[in] method The numerical method to use. The default is set in the options * */ -Coordinates::FieldMetric Vpar_Grad_par(const Field2D& v, const Field2D& f, - CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT"); +bout::FieldMetric Vpar_Grad_par(const Field2D& v, const Field2D& f, + CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT"); -inline Coordinates::FieldMetric Vpar_Grad_par(const Field2D& v, const Field2D& f, - CELL_LOC outloc, DIFF_METHOD method) { +inline bout::FieldMetric Vpar_Grad_par(const Field2D& v, const Field2D& f, + CELL_LOC outloc, DIFF_METHOD method) { return Vpar_Grad_par(v, f, outloc, toString(method)); } @@ -118,11 +119,10 @@ inline Field3D Vpar_Grad_par(const Field3D& v, const Field3D& f, CELL_LOC outloc * @param[in] method The numerical method to use * */ -Coordinates::FieldMetric Div_par(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT"); +bout::FieldMetric Div_par(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT"); -inline Coordinates::FieldMetric Div_par(const Field2D& f, CELL_LOC outloc, - DIFF_METHOD method) { +inline bout::FieldMetric Div_par(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method) { return Div_par(f, outloc, toString(method)); } @@ -160,10 +160,10 @@ inline Field3D Div_par_flux(const Field3D& v, const Field3D& f, CELL_LOC outloc, * @param[in] f The field to be differentiated * @param[in] outloc The cell location of the result */ -Coordinates::FieldMetric Grad2_par2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT"); -inline Coordinates::FieldMetric Grad2_par2(const Field2D& f, CELL_LOC outloc, - DIFF_METHOD method) { +bout::FieldMetric Grad2_par2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT"); +inline bout::FieldMetric Grad2_par2(const Field2D& f, CELL_LOC outloc, + DIFF_METHOD method) { return Grad2_par2(f, outloc, toString(method)); } @@ -183,11 +183,11 @@ inline Field3D Grad2_par2(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method) * @param[in] kY The diffusion coefficient * @param[in] f The field whose gradient drives a flux */ -Coordinates::FieldMetric Div_par_K_Grad_par(BoutReal kY, const Field2D& f, - CELL_LOC outloc = CELL_DEFAULT); +bout::FieldMetric Div_par_K_Grad_par(BoutReal kY, const Field2D& f, + CELL_LOC outloc = CELL_DEFAULT); Field3D Div_par_K_Grad_par(BoutReal kY, const Field3D& f, CELL_LOC outloc = CELL_DEFAULT); -Coordinates::FieldMetric Div_par_K_Grad_par(const Field2D& kY, const Field2D& f, - CELL_LOC outloc = CELL_DEFAULT); +bout::FieldMetric Div_par_K_Grad_par(const Field2D& kY, const Field2D& f, + CELL_LOC outloc = CELL_DEFAULT); Field3D Div_par_K_Grad_par(const Field2D& kY, const Field3D& f, CELL_LOC outloc = CELL_DEFAULT); Field3D Div_par_K_Grad_par(const Field3D& kY, const Field2D& f, @@ -209,8 +209,8 @@ Field3D Div_par_K_Grad_par_mod(const Field3D& k, const Field3D& f, Field3D& flow * * For the full perpendicular Laplacian, use Laplace_perp */ -Coordinates::FieldMetric Delp2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - bool useFFT = true); +bout::FieldMetric Delp2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + bool useFFT = true); Field3D Delp2(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, bool useFFT = true); FieldPerp Delp2(const FieldPerp& f, CELL_LOC outloc = CELL_DEFAULT, bool useFFT = true); @@ -219,10 +219,9 @@ FieldPerp Delp2(const FieldPerp& f, CELL_LOC outloc = CELL_DEFAULT, bool useFFT * * */ -Coordinates::FieldMetric -Laplace_perp(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& dfdy_boundary_condition = "free_o3", - const std::string& dfdy_region = ""); +bout::FieldMetric Laplace_perp(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& dfdy_boundary_condition = "free_o3", + const std::string& dfdy_region = ""); Field3D Laplace_perp(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& dfdy_boundary_condition = "free_o3", const std::string& dfdy_region = ""); @@ -231,15 +230,15 @@ Field3D Laplace_perp(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, * Parallel Laplacian operator * */ -Coordinates::FieldMetric Laplace_par(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT); +bout::FieldMetric Laplace_par(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT); Field3D Laplace_par(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT); /*! * Full Laplacian operator (par + perp) */ -Coordinates::FieldMetric Laplace(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& dfdy_boundary_condition = "free_o3", - const std::string& dfdy_region = ""); +bout::FieldMetric Laplace(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& dfdy_boundary_condition = "free_o3", + const std::string& dfdy_region = ""); Field3D Laplace(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& dfdy_boundary_condition = "free_o3", const std::string& dfdy_region = ""); @@ -253,8 +252,8 @@ Field2D Laplace_perpXY(const Field2D& A, const Field2D& f); * Terms of form b0 x Grad(phi) dot Grad(A) * */ -Coordinates::FieldMetric b0xGrad_dot_Grad(const Field2D& phi, const Field2D& A, - CELL_LOC outloc = CELL_DEFAULT); +bout::FieldMetric b0xGrad_dot_Grad(const Field2D& phi, const Field2D& A, + CELL_LOC outloc = CELL_DEFAULT); /*! * Terms of form @@ -304,10 +303,9 @@ constexpr BRACKET_METHOD BRACKET_CTU = BRACKET_METHOD::ctu; * @param[in] solver Pointer to the time integration solver * */ -Coordinates::FieldMetric bracket(const Field2D& f, const Field2D& g, - BRACKET_METHOD method = BRACKET_STD, - CELL_LOC outloc = CELL_DEFAULT, - Solver* solver = nullptr); +bout::FieldMetric bracket(const Field2D& f, const Field2D& g, + BRACKET_METHOD method = BRACKET_STD, + CELL_LOC outloc = CELL_DEFAULT, Solver* solver = nullptr); Field3D bracket(const Field2D& f, const Field3D& g, BRACKET_METHOD method = BRACKET_STD, CELL_LOC outloc = CELL_DEFAULT, Solver* solver = nullptr); Field3D bracket(const Field3D& f, const Field2D& g, BRACKET_METHOD method = BRACKET_STD, diff --git a/include/bout/field.hxx b/include/bout/field.hxx index b39a82eb0b..96c17a1193 100644 --- a/include/bout/field.hxx +++ b/include/bout/field.hxx @@ -134,12 +134,15 @@ public: virtual void setRegion([[maybe_unused]] std::optional regionID) {} virtual void setRegion([[maybe_unused]] const std::string& region_name) {} virtual void resetRegion() {} + virtual void resetRegionParallel([[maybe_unused]] bool force) {}; virtual std::optional getRegionID() const { return {}; } virtual bool hasParallelSlices() const { return true; } virtual void calcParallelSlices() {} virtual void splitParallelSlices() {} virtual void clearParallelSlices() {} virtual size_t numberParallelSlices() const { return 0; } + virtual bool areCalcParallelSlicesAllowed() const { return false; } + virtual void disallowCalcParallelSlices() {} private: /// Labels for the type of coordinate system this field is defined over diff --git a/include/bout/field3d.hxx b/include/bout/field3d.hxx index 905e736999..d60ba4b281 100644 --- a/include/bout/field3d.hxx +++ b/include/bout/field3d.hxx @@ -355,7 +355,7 @@ public: const Region& getValidRegionWithDefault(const std::string& region_name) const; void setRegion(const std::string& region_name) override; void resetRegion() override { regionID.reset(); }; - void resetRegionParallel(bool force = false); + void resetRegionParallel(bool force = false) override; void setRegion(size_t id) override { regionID = id; }; void setRegion(std::optional id) override { regionID = id; }; std::optional getRegionID() const override { return regionID; }; @@ -601,6 +601,8 @@ public: friend class Vector2D; void calcParallelSlices() override; + bool areCalcParallelSlicesAllowed() const override { return _allowCalcParallelSlices; }; + void disallowCalcParallelSlices() override { _allowCalcParallelSlices = false; }; void applyBoundary(bool init = false) override; void applyBoundary(BoutReal t); @@ -633,9 +635,6 @@ public: std::weak_ptr getTracking() { return tracking; }; - bool areCalcParallelSlicesAllowed() const { return _allowCalcParallelSlices; }; - void disallowCalcParallelSlices() { _allowCalcParallelSlices = false; }; - inline Field3DParallel asField3DParallel(); inline Field3DParallel asField3DParallel() const; diff --git a/include/bout/fv_ops_impl.hxx b/include/bout/fv_ops_impl.hxx index 1b7a36f874..a4e8f908bf 100644 --- a/include/bout/fv_ops_impl.hxx +++ b/include/bout/fv_ops_impl.hxx @@ -491,10 +491,14 @@ Field3D Div_f_v(const Field3D& n_in, const Vector3D& v, bool bndry_flux) { BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { // Calculate velocities - const BoutReal vU = 0.25 * (vz[i.zp()] + vz[i]) * (coord->J[i.zp()] + coord->J[i]); - const BoutReal vD = 0.25 * (vz[i.zm()] + vz[i]) * (coord->J[i.zm()] + coord->J[i]); - const BoutReal vL = 0.25 * (vx[i.xm()] + vx[i]) * (coord->J[i.xm()] + coord->J[i]); - const BoutReal vR = 0.25 * (vx[i.xp()] + vx[i]) * (coord->J[i.xp()] + coord->J[i]); + const BoutReal vU = + 0.25 * (vz[i.zp()] + vz[i]) * (coord->J()[i.zp()] + coord->J()[i]); + const BoutReal vD = + 0.25 * (vz[i.zm()] + vz[i]) * (coord->J()[i.zm()] + coord->J()[i]); + const BoutReal vL = + 0.25 * (vx[i.xm()] + vx[i]) * (coord->J()[i.xm()] + coord->J()[i]); + const BoutReal vR = + 0.25 * (vx[i.xp()] + vx[i]) * (coord->J()[i.xp()] + coord->J()[i]); // X direction Stencil1D s; @@ -517,16 +521,16 @@ 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 const 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()]); } } @@ -544,15 +548,15 @@ 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) { const 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()]); } } @@ -568,13 +572,13 @@ Field3D Div_f_v(const Field3D& n_in, const Vector3D& v, bool bndry_flux) { if (vU > 0.0) { const 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) { const 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()]); } } @@ -592,15 +596,17 @@ 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 - const BoutReal vU = 0.25 * (vy[i] + vy[i.yp()]) * (coord->J[i] + coord->J[i.yp()]); - const BoutReal vD = 0.25 * (vy[i] + vy[i.ym()]) * (coord->J[i] + coord->J[i.ym()]); + const BoutReal vU = + 0.25 * (vy[i] + vy[i.yp()]) * (coord->J()[i] + coord->J()[i.yp()]); + const 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 const BoutReal nU = 0.5 * (n[i] + n[i.yp()]); const 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"); } @@ -823,9 +829,9 @@ Field3D Div_par_fvv(const Field3D& f_in, const Field3D& v_in, ASSERT1(f_in.hasParallelSlices()); ASSERT1(v_in.hasParallelSlices()); - const auto& B = coord->Bxy; - const auto& B_up = coord->Bxy.yup(); - const auto& B_down = coord->Bxy.ydown(); + const auto& B = coord->Bxy(); + const auto& B_up = coord->Bxy().yup(); + const auto& B_down = coord->Bxy().ydown(); const auto& f_up = f_in.yup(); const auto& f_down = f_in.ydown(); @@ -833,8 +839,8 @@ Field3D Div_par_fvv(const Field3D& f_in, const Field3D& v_in, const auto& v_up = v_in.yup(); const auto& v_down = v_in.ydown(); - const auto& g_22 = coord->g_22; - const auto& dy = coord->dy; + const auto& g_22 = coord->g_22(); + const auto& dy = coord->dy(); Field3D result{emptyFrom(f_in)}; BOUT_FOR(i, f_in.getRegion("RGN_NOBNDRY")) { @@ -1013,9 +1019,9 @@ Field3D Div_par_fvv_heating(const Field3D& f_in, const Field3D& v_in, ASSERT1(f_in.hasParallelSlices()); ASSERT1(v_in.hasParallelSlices()); - const auto B = coord->Bxy; - const auto B_up = coord->Bxy.yup(); - const auto B_down = coord->Bxy.ydown(); + const auto B = coord->Bxy(); + const auto B_up = coord->Bxy().yup(); + const auto B_down = coord->Bxy().ydown(); const auto& f_up = f_in.yup(); const auto& f_down = f_in.ydown(); @@ -1023,8 +1029,8 @@ Field3D Div_par_fvv_heating(const Field3D& f_in, const Field3D& v_in, const auto& v_up = v_in.yup(); const auto& v_down = v_in.ydown(); - const auto g_22 = coord->g_22; - const auto dy = coord->dy; + const auto g_22 = coord->g_22(); + const auto dy = coord->dy(); Field3D result{emptyFrom(f_in)}; flow_ylow = zeroFrom(f_in); @@ -1336,10 +1342,10 @@ Field3D Div_a_Grad_perp_limit(const Field3D& a, const Field3D& g, const Field3D& if (fci) { // 3D Metric, need yup/ydown fields. // Requires previous communication of metrics. - 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?"); + 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!"); } } #endif @@ -1357,12 +1363,12 @@ Field3D Div_a_Grad_perp_limit(const Field3D& a, const Field3D& g, const Field3D& #else constexpr bool metric_fci = false; #endif - 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); 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 84f9ec36c6..ed1dff68b7 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -624,25 +624,7 @@ public: return getCoordinatesSmart(location).get(); }; - std::shared_ptr - getCoordinatesSmart(const CELL_LOC location = CELL_CENTRE) { - ASSERT1(location != CELL_DEFAULT); - ASSERT1(location != CELL_VSHIFT); - - auto found = coords_map.find(location); - if (found != coords_map.end()) { - // True branch most common, returns immediately - return found->second; - } - - // No coordinate system set. Create default - // 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); - return inserted.first->second; - } + std::shared_ptr getCoordinatesSmart(CELL_LOC location = CELL_CENTRE); std::shared_ptr getCoordinatesConst(const CELL_LOC location = CELL_CENTRE) const { diff --git a/include/bout/metric_tensor.hxx b/include/bout/metric_tensor.hxx new file mode 100644 index 0000000000..9e510f2bb9 --- /dev/null +++ b/include/bout/metric_tensor.hxx @@ -0,0 +1,103 @@ +#ifndef BOUT_METRIC_TENSOR_HXX +#define BOUT_METRIC_TENSOR_HXX + +#include +#include +#include +#include + +#include + +namespace bout { +#if BOUT_USE_METRIC_3D +using FieldMetric = Field3D; +#else +using FieldMetric = Field2D; +#endif +} // namespace bout + +class Coordinates; + +class MetricTensor { +public: + friend class Coordinates; + +#if BOUT_USE_METRIC_3D + using Metric2DSlice = const BoutReal*; +#else + using Metric2DSlice = const BoutReal&; +#endif + using FieldMetric = bout::FieldMetric; + + MetricTensor(const MetricTensor&) = default; + MetricTensor(MetricTensor&&) = default; + MetricTensor& operator=(const MetricTensor&) = default; + MetricTensor& operator=(MetricTensor&&) = default; + 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); + virtual ~MetricTensor() = default; + + /// 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); } + + /// 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(); + +private: + FieldMetric g11_m, g22_m, g33_m, g12_m, g13_m, g23_m; +}; + +class CovariantMetricTensor; +class ContravariantMetricTensor; + +class CovariantMetricTensor : public MetricTensor { +public: + using MetricTensor::MetricTensor; + + auto inverse(const std::string& region = "RGN_ALL", bool communicate = true) + -> ContravariantMetricTensor; +}; + +class ContravariantMetricTensor : public MetricTensor { +public: + using MetricTensor::MetricTensor; + + auto inverse(const std::string& region = "RGN_ALL", bool communicate = true) + -> CovariantMetricTensor; +}; + +#endif //BOUT_METRIC_TENSOR_HXX diff --git a/include/bout/parallel_boundary_op.hxx b/include/bout/parallel_boundary_op.hxx index 5139cd5090..d98aa7d4e8 100644 --- a/include/bout/parallel_boundary_op.hxx +++ b/include/bout/parallel_boundary_op.hxx @@ -211,7 +211,7 @@ public: void apply(Field3D& f, BoutReal t) override { if (bndry != nullptr) { f.ynext(bndry->dir()).allocate(); // Ensure unique before modifying - auto dy = f.getCoordinates()->dy; + auto dy = f.getCoordinates()->dy(); for (auto pnt : *bndry) { BoutReal value = getValue(pnt, t); if (isNeumann) { @@ -222,7 +222,7 @@ public: } if (bndryX != nullptr) { f.allocate(); - auto dy = f.getCoordinates()->dx; + auto dy = f.getCoordinates()->dx(); for (auto pnt : *bndryX) { BoutReal value = getValue(pnt, t); if (isNeumann) { @@ -233,7 +233,7 @@ public: } if (bndryY != nullptr) { f.allocate(); - auto dy = f.getCoordinates()->dy; + auto dy = f.getCoordinates()->dy(); for (auto pnt : *bndryY) { BoutReal value = getValue(pnt, t); if (isNeumann) { diff --git a/include/bout/paralleltransform.hxx b/include/bout/paralleltransform.hxx index d9ed397bb5..6952069251 100644 --- a/include/bout/paralleltransform.hxx +++ b/include/bout/paralleltransform.hxx @@ -91,10 +91,6 @@ public: /// require a twist-shift at branch cuts on closed field lines? virtual bool requiresTwistShift(bool twist_shift_enabled, YDirectionType ytype) = 0; - /// Can be implemented to load parallel metrics - /// Needed by FCI - virtual void loadParallelMetrics([[maybe_unused]] Coordinates* coords) {} - protected: /// This method should be called in the constructor to check that if the grid /// has a 'parallel_transform' variable, it has the correct value diff --git a/include/bout/tokamak_coordinates.hxx b/include/bout/tokamak_coordinates.hxx index f056033bb9..295d0bf9d1 100644 --- a/include/bout/tokamak_coordinates.hxx +++ b/include/bout/tokamak_coordinates.hxx @@ -4,6 +4,7 @@ #include #include #include +#include class Mesh; @@ -14,21 +15,21 @@ namespace bout { /// `I_unnormalised` are normalised. struct TokamakCoordinates { /// Major radius - Field2D Rxy; + FieldMetric Rxy; /// Vertical height - Field2D Zxy; + FieldMetric Zxy; /// Poloidal magnetic field - Field2D Bpxy; + FieldMetric Bpxy; /// Toroidal magnetic field - Field2D Btxy; + FieldMetric Btxy; /// Total magnetic field - Field2D Bxy; + FieldMetric Bxy; /// Poloidal arc length - Field2D hthe; + FieldMetric hthe; /// Integrated shear (normalised) - Coordinates::FieldMetric I; + FieldMetric I; /// Unnormalised integrated shear - Coordinates::FieldMetric I_unnormalised; + FieldMetric I_unnormalised; }; /// Read, normalise, calculate, and set the metric components for a BOUT++ diff --git a/src/field/vecops.cxx b/src/field/vecops.cxx index 672e8f6c09..1bb3d991f4 100644 --- a/src/field/vecops.cxx +++ b/src/field/vecops.cxx @@ -104,10 +104,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()); @@ -126,9 +126,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()); @@ -159,10 +159,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(Coordinates::FieldMetric{metric->J * vcn.y}, outloc, method); - result += DDZ(Coordinates::FieldMetric{metric->J * vcn.z}, outloc, method); - result /= metric->J; + Coordinates::FieldMetric result = DDX(metric->J() * vcn.x, outloc, method); + result += DDY(Coordinates::FieldMetric{metric->J() * vcn.y}, outloc, method); + result += DDZ(Coordinates::FieldMetric{metric->J() * vcn.z}, outloc, method); + result /= metric->J(); return result; } @@ -185,7 +185,7 @@ Field3D Div(const Vector3D& v, CELL_LOC outloc, const std::string& method) { Vector3D vcn = v; vcn.toContravariant(); - Field3D vcnJy = vcn.y.getCoordinates()->J * vcn.y; + Field3D 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 @@ -194,9 +194,9 @@ Field3D Div(const Vector3D& v, CELL_LOC outloc, const std::string& method) { } auto result = DDY(vcnJy, outloc, method); - result += DDX(Field3D{vcn.x.getCoordinates()->J * vcn.x}, outloc, method); - result += DDZ(Field3D{vcn.z.getCoordinates()->J * vcn.z}, outloc, method); - result /= metric->J; + result += DDX(Field3D{vcn.x.getCoordinates()->J() * vcn.x}, outloc, method); + result += DDZ(Field3D{vcn.z.getCoordinates()->J() * vcn.z}, outloc, method); + result /= metric->J(); return result; } @@ -224,12 +224,12 @@ Coordinates::FieldMetric Div(const Vector2D& v, const Field2D& f, CELL_LOC outlo vcn.toContravariant(); Coordinates::FieldMetric result = FDDX( - Coordinates::FieldMetric{vcn.x.getCoordinates()->J * vcn.x}, f, outloc, method); - result += FDDY(Coordinates::FieldMetric{vcn.y.getCoordinates()->J * vcn.y}, f, outloc, + Coordinates::FieldMetric{vcn.x.getCoordinates()->J() * vcn.x}, f, outloc, method); + result += FDDY(Coordinates::FieldMetric{vcn.y.getCoordinates()->J() * vcn.y}, f, outloc, method); - result += FDDZ(Coordinates::FieldMetric{vcn.z.getCoordinates()->J * vcn.z}, f, outloc, + result += FDDZ(Coordinates::FieldMetric{vcn.z.getCoordinates()->J() * vcn.z}, f, outloc, method); - result /= metric->J; + result /= metric->J(); return result; } @@ -250,10 +250,10 @@ Field3D Div(const Vector3D& v, const Field3D& f, CELL_LOC outloc, Vector3D vcn = v; vcn.toContravariant(); - Field3D result = FDDX(Field3D{vcn.x.getCoordinates()->J * vcn.x}, f, outloc, method); - result += FDDY(Field3D{vcn.y.getCoordinates()->J * vcn.y}, f, outloc, method); - result += FDDZ(Field3D{vcn.z.getCoordinates()->J * vcn.z}, f, outloc, method); - result /= metric->J; + Field3D result = FDDX(Field3D{vcn.x.getCoordinates()->J() * vcn.x}, f, outloc, method); + result += FDDY(Field3D{vcn.y.getCoordinates()->J() * vcn.y}, f, outloc, method); + result += FDDZ(Field3D{vcn.z.getCoordinates()->J() * vcn.z}, f, outloc, method); + result /= metric->J(); return result; } @@ -274,12 +274,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()); @@ -302,12 +302,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()); @@ -387,80 +387,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..d6182117ff 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,16 +28,26 @@ * **************************************************************************/ -#include - +#include #include +#include #include +#include +#include +#include +#include #include +#include +#include #include #include +#include +#include +#include + Vector2D::Vector2D(const Vector2D& f) - : FieldData(f), x(f.x), y(f.y), z(f.z), covariant(f.covariant), deriv(nullptr), + : FieldData(f), x(f.x), y(f.y), z(f.z), covariant(f.covariant), location(f.getLocation()) {} Vector2D::Vector2D(Mesh* localmesh, bool covariant, CELL_LOC location) @@ -67,10 +77,9 @@ 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 +95,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); + auto* const metric = localmesh->getCoordinates(location); // Need to use temporary arrays to store result - Coordinates::FieldMetric gx{emptyFrom(x)}, gy{emptyFrom(y)}, gz{emptyFrom(z)}; + bout::FieldMetric gx{emptyFrom(x)}; + bout::FieldMetric gy{emptyFrom(y)}; + bout::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,11 +134,9 @@ 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 @@ -140,24 +152,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); + auto* const metric = localmesh->getCoordinates(location); // Need to use temporary arrays to store result - Coordinates::FieldMetric gx{emptyFrom(x)}, gy{emptyFrom(y)}, gz{emptyFrom(z)}; + bout::FieldMetric gx{emptyFrom(x)}; + bout::FieldMetric gy{emptyFrom(y)}; + bout::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 +214,7 @@ Vector2D* Vector2D::timeDeriv() { } /*************************************************************** - * OPERATORS + * OPERATORS ***************************************************************/ /////////////////// ASSIGNMENT //////////////////// @@ -303,7 +320,7 @@ Vector2D& Vector2D::operator/=(const Field2D& rhs) { } /*************************************************************** - * BINARY OPERATORS + * BINARY OPERATORS ***************************************************************/ ////////////////// ADDITION ////////////////////// @@ -386,22 +403,22 @@ const Coordinates::FieldMetric Vector2D::operator*(const Vector2D& rhs) const { result = x * rhs.x + y * rhs.y + z * rhs.z; } else { // Both are covariant or contravariant - Coordinates* metric = localmesh->getCoordinates(location); + const Coordinates* metric = localmesh->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/field/vector3d.cxx b/src/field/vector3d.cxx index 7fb4a88918..fc61ab2a24 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,17 +28,24 @@ * **************************************************************************/ -#include - #include #include +#include #include +#include +#include +#include +#include #include +#include #include #include +#include +#include + Vector3D::Vector3D(const Vector3D& f) - : FieldData(f), x(f.x), y(f.y), z(f.z), covariant(f.covariant), deriv(nullptr), + : FieldData(f), x(f.x), y(f.y), z(f.z), covariant(f.covariant), location(f.getLocation()) {} Vector3D::Vector3D(Mesh* localmesh, bool covariant, CELL_LOC location) @@ -68,10 +75,9 @@ void Vector3D::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 @@ -87,23 +93,28 @@ 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); + auto* const 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->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,11 +132,9 @@ 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 @@ -141,24 +150,29 @@ void Vector3D::toContravariant() { // 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]; + 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); + auto* const 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 +213,7 @@ Vector3D* Vector3D::timeDeriv() { } /*************************************************************** - * OPERATORS + * OPERATORS ***************************************************************/ /////////////////// ASSIGNMENT //////////////////// @@ -379,9 +393,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 +407,7 @@ CROSS(Vector3D, Vector2D, Vector3D) CROSS(Vector2D, Vector2D, Vector2D) /*************************************************************** - * BINARY OPERATORS + * BINARY OPERATORS ***************************************************************/ ////////////////// ADDITION ////////////////////// @@ -482,18 +496,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 +528,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..6a321b0adf 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 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. @@ -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/naulin/naulin_laplace.cxx b/src/invert/laplace/impls/naulin/naulin_laplace.cxx index 3faba2f0ea..c5c2a19915 100644 --- a/src/invert/laplace/impls/naulin/naulin_laplace.cxx +++ b/src/invert/laplace/impls/naulin/naulin_laplace.cxx @@ -189,8 +189,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 9966ad654d..d254ea4a68 100644 --- a/src/invert/laplace/impls/petsc3damg/petsc3damg.cxx +++ b/src/invert/laplace/impls/petsc3damg/petsc3damg.cxx @@ -24,14 +24,15 @@ * along with BOUT++. If not, see . * **************************************************************************/ -#include "bout/bout_types.hxx" -#include "bout/build_defines.hxx" + +#include #if BOUT_HAS_PETSC #include "petsc3damg.hxx" #include +#include #include #include #include @@ -40,6 +41,8 @@ #include #include +#include + using bout::utils::flagSet; #ifdef PETSC_HAVE_HYPRE @@ -122,7 +125,7 @@ LaplacePetsc3dAmg::LaplacePetsc3dAmg(Options* opt, const CELL_LOC loc, Mesh* mes const bool inner_X_neumann = isInnerBoundaryFlagSet(INVERT_AC_GRAD); if (inner_X_neumann) { // This is a BinaryExpr that is only evaluated when needed - const auto inner_X_BC = -1. / coords->dx / sqrt(coords->g_11); + const auto inner_X_BC = -1. / coords->dx() / sqrt(coords->g_11()); BOUT_FOR_SERIAL(i, indexer->getRegionInnerX()) { const BoutReal bc = inner_X_BC[i]; operator3D(i, i) = bc; @@ -137,7 +140,7 @@ LaplacePetsc3dAmg::LaplacePetsc3dAmg(Options* opt, const CELL_LOC loc, Mesh* mes const bool outer_X_neumann = isOuterBoundaryFlagSet(INVERT_AC_GRAD); if (outer_X_neumann) { - const auto outer_X_BC = 1. / coords->dx / sqrt(coords->g_11); + const auto outer_X_BC = 1. / coords->dx() / sqrt(coords->g_11()); BOUT_FOR_SERIAL(i, indexer->getRegionOuterX()) { const BoutReal bc = outer_X_BC[i]; operator3D(i, i) = bc; @@ -152,7 +155,7 @@ LaplacePetsc3dAmg::LaplacePetsc3dAmg(Options* opt, const CELL_LOC loc, Mesh* mes const bool lower_Y_neumann = flagSet(lower_boundary_flags, INVERT_AC_GRAD); if (lower_Y_neumann) { - const auto lower_Y_BC = -1. / coords->dy / sqrt(coords->g_22); + const auto lower_Y_BC = -1. / coords->dy() / sqrt(coords->g_22()); BOUT_FOR_SERIAL(i, indexer->getRegionLowerY()) { const BoutReal bc = lower_Y_BC[i]; operator3D(i, i) = bc; @@ -167,7 +170,7 @@ LaplacePetsc3dAmg::LaplacePetsc3dAmg(Options* opt, const CELL_LOC loc, Mesh* mes const bool upper_Y_neumann = flagSet(upper_boundary_flags, INVERT_AC_GRAD); if (upper_Y_neumann) { - const auto upper_Y_BC = 1. / coords->dy / sqrt(coords->g_22); + const auto upper_Y_BC = 1. / coords->dy() / sqrt(coords->g_22()); BOUT_FOR_SERIAL(i, indexer->getRegionUpperY()) { const BoutReal bc = upper_Y_BC[i]; operator3D(i, i) = bc; @@ -299,7 +302,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(Coordinates::FieldMetric{coords->J / coords->g_22}); + const auto dJ_dy = DDY(Coordinates::FieldMetric{coords->J() / coords->g_22()}); // Set up the matrix for the internal points on the grid. // Boundary conditions were set in the constructor. @@ -308,18 +311,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) { @@ -327,32 +330,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; @@ -384,24 +387,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]; @@ -409,15 +412,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 @@ -427,10 +430,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 9af6fd20f9..0ec5f471da 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); diff --git a/src/invert/laplacexy/impls/hypre/laplacexy-hypre.cxx b/src/invert/laplacexy/impls/hypre/laplacexy-hypre.cxx index 61632a332d..fbba16673c 100644 --- a/src/invert/laplacexy/impls/hypre/laplacexy-hypre.cxx +++ b/src/invert/laplacexy/impls/hypre/laplacexy-hypre.cxx @@ -113,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 @@ -139,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..916dc0c6af 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]); + const 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]); + const 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]); + const 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]); + const 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..2048bb587f 100644 --- a/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx +++ b/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx @@ -5,11 +5,11 @@ #include #include +#include +#include #include #include -#include - LaplaceXZcyclic::LaplaceXZcyclic(Mesh* m, Options* options, const CELL_LOC loc) : LaplaceXZ(m, options, loc) { // Note: `m` may be nullptr, but localmesh is set in LaplaceXZ base constructor @@ -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 141cab0a43..56eec912b5 100644 --- a/src/mesh/boundary_standard.cxx +++ b/src/mesh/boundary_standard.cxx @@ -2661,8 +2661,8 @@ void BoundaryNeumann::apply([[maybe_unused]] Field2D& f, [[maybe_unused]] BoutRe rfft(f(x - 2 * bx, y), mesh->LocalNz, c1.begin()); c1[0] = c0[0] - c1[0]; // Only need gradient - // Solve metric->g11*d2f/dx2 - metric->g33*kz^2f = 0 - // Assume metric->g11, metric->g33 constant -> exponential growth or decay + // Solve metric->g11()*d2f/dx2 - metric->g33()*kz^2f = 0 + // Assume metric->g11(), metric->g33() constant -> exponential growth or decay // Loop in X towards edge of domain do { @@ -2878,8 +2878,8 @@ void BoundaryNeumann::apply([[maybe_unused]] Field2D& f, [[maybe_unused]] BoutRe c1[jz] = la * c2[jz] + lb * c1[jz] + lc * c0[jz]; } } - // Solve metric->g11*d2f/dx2 - metric->g33*kz^2f = 0 - // Assume metric->g11, metric->g33 constant -> exponential growth or decay + // Solve metric->g11()*d2f/dx2 - metric->g33()*kz^2f = 0 + // Assume metric->g11(), metric->g33() constant -> exponential growth or decay BoutReal xpos = 0.0; // Loop in X towards edge of domain do { @@ -2976,7 +2976,7 @@ void BoundaryNeumann::apply([[maybe_unused]] Field2D& f, [[maybe_unused]] BoutRe var.z(jx + 1, jy, jz) = var.z(jx - 3, jy, jz) + 4. * metric->dx(jx, jy) * tmp; } - // d/dx( Jmetric->g11 B_x ) = - d/dx( Jmetric->g12 B_y + Jmetric->g13 B_z) + // 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 = diff --git a/src/mesh/christoffel_symbols.cxx b/src/mesh/christoffel_symbols.cxx new file mode 100644 index 0000000000..c90d7c6d58 --- /dev/null +++ b/src/mesh/christoffel_symbols.cxx @@ -0,0 +1,92 @@ +#include "bout/christoffel_symbols.hxx" +#include "bout/coordinates.hxx" +#include "bout/derivs.hxx" +#include "bout/mesh.hxx" +#include "bout/output.hxx" + +ChristoffelSymbols::ChristoffelSymbols(const Coordinates& coordinates) { + // Calculate Christoffel symbol terms (18 independent values) + // Note: This calculation is completely general: metric + // tensor can be 2D or 3D. For 2D, all DDZ terms are zero + + const auto& contravariantMetricTensor = coordinates.getContravariantMetricTensor(); + const auto& covariantMetricTensor = coordinates.getCovariantMetricTensor(); + + const auto& g11 = contravariantMetricTensor.g11(); + const auto& g22 = contravariantMetricTensor.g22(); + const auto& g33 = contravariantMetricTensor.g33(); + const auto& g12 = contravariantMetricTensor.g12(); + const auto& g13 = contravariantMetricTensor.g13(); + const auto& g23 = contravariantMetricTensor.g23(); + + const auto& g_11 = covariantMetricTensor.g11(); + const auto& g_22 = covariantMetricTensor.g22(); + const auto& g_33 = covariantMetricTensor.g33(); + const auto& g_12 = covariantMetricTensor.g12(); + const auto& g_13 = covariantMetricTensor.g13(); + const auto& g_23 = covariantMetricTensor.g23(); + + G1_11_m = 0.5 * g11 * DDX(g_11) + g12 * (DDX(g_12) - 0.5 * DDY(g_11)) + + g13 * (DDX(g_13) - 0.5 * DDZ(g_11)); + G1_22_m = g11 * (DDY(g_12) - 0.5 * DDX(g_22)) + 0.5 * g12 * DDY(g_22) + + g13 * (DDY(g_23) - 0.5 * DDZ(g_22)); + G1_33_m = g11 * (DDZ(g_13) - 0.5 * DDX(g_33)) + g12 * (DDZ(g_23) - 0.5 * DDY(g_33)) + + 0.5 * g13 * DDZ(g_33); + G1_12_m = 0.5 * g11 * DDY(g_11) + 0.5 * g12 * DDX(g_22) + + 0.5 * g13 * (DDY(g_13) + DDX(g_23) - DDZ(g_12)); + G1_13_m = 0.5 * g11 * DDZ(g_11) + 0.5 * g12 * (DDZ(g_12) + DDX(g_23) - DDY(g_13)) + + 0.5 * g13 * DDX(g_33); + G1_23_m = 0.5 * g11 * (DDZ(g_12) + DDY(g_13) - DDX(g_23)) + + 0.5 * g12 * (DDZ(g_22) + DDY(g_23) - DDY(g_23)) + // + 0.5 *g13*(DDZ(g_32) + DDY(g_33) - DDZ(g_23)); + // which equals + + 0.5 * g13 * DDY(g_33); + + G2_11_m = 0.5 * g12 * DDX(g_11) + g22 * (DDX(g_12) - 0.5 * DDY(g_11)) + + g23 * (DDX(g_13) - 0.5 * DDZ(g_11)); + G2_22_m = g12 * (DDY(g_12) - 0.5 * DDX(g_22)) + 0.5 * g22 * DDY(g_22) + + g23 * (DDY(g23) - 0.5 * DDZ(g_22)); + G2_33_m = g12 * (DDZ(g_13) - 0.5 * DDX(g_33)) + g22 * (DDZ(g_23) - 0.5 * DDY(g_33)) + + 0.5 * g23 * DDZ(g_33); + G2_12_m = 0.5 * g12 * DDY(g_11) + 0.5 * g22 * DDX(g_22) + + 0.5 * g23 * (DDY(g_13) + DDX(g_23) - DDZ(g_12)); + G2_13_m = + // 0.5 *g21*(DDZ(g_11) + DDX(covariantMetricTensor.Getg13()) - DDX(g_13)) + // which equals + 0.5 * g12 * (DDZ(g_11) + DDX(g_13) - DDX(g_13)) + // + 0.5 *g22*(DDZ(covariantMetricTensor.Getg21()) + DDX(g_23) - DDY(g_13)) + // which equals + + 0.5 * g22 * (DDZ(g_12) + DDX(g_23) - DDY(g_13)) + // + 0.5 *g23*(DDZ(covariantMetricTensor.Getg31()) + DDX(g_33) - DDZ(g_13)); + // which equals + + 0.5 * g23 * DDX(g_33); + G2_23_m = 0.5 * g12 * (DDZ(g_12) + DDY(g_13) - DDX(g_23)) + 0.5 * g22 * DDZ(g_22) + + 0.5 * g23 * DDY(g_33); + + G3_11_m = 0.5 * g13 * DDX(g_11) + g23 * (DDX(g_12) - 0.5 * DDY(g_11)) + + g33 * (DDX(g_13) - 0.5 * DDZ(g_11)); + G3_22_m = g13 * (DDY(g_12) - 0.5 * DDX(g_22)) + 0.5 * g23 * DDY(g_22) + + g33 * (DDY(g_23) - 0.5 * DDZ(g_22)); + G3_33_m = g13 * (DDZ(g_13) - 0.5 * DDX(g_33)) + g23 * (DDZ(g_23) - 0.5 * DDY(g_33)) + + 0.5 * g33 * DDZ(g_33); + G3_12_m = + // 0.5 *g31*(DDY(g_11) + DDX(covariantMetricTensor.Getg12()) - DDX(g_12)) + // which equals to + 0.5 * g13 * DDY(g_11) + // + 0.5 *g32*(DDY(covariantMetricTensor.Getg21()) + DDX(g_22) - DDY(g_12)) + // which equals to + + 0.5 * g23 * DDX(g_22) + //+ 0.5 *g33*(DDY(covariantMetricTensor.Getg31()) + DDX(covariantMetricTensor.Getg32()) - DDZ(g_12)); + // which equals to + + 0.5 * g33 * (DDY(g_13)) + DDX(g_23) - DDZ(g_12); + G3_13_m = 0.5 * g13 * DDZ(g_11) + 0.5 * g23 * (DDZ(g_12) + DDX(g_23) - DDY(g_13)) + + 0.5 * g33 * DDX(g_33); + G3_23_m = 0.5 * g13 * (DDZ(g_12) + DDY(g_13)) - DDX(g_23) + 0.5 * g23 * DDZ(g_22) + + 0.5 * g33 * DDY(g_33); + + output_progress.write("\tCommunicating connection terms\n"); + + G1_11_m.getMesh()->communicate(G1_11_m, G1_22_m, G1_33_m, G1_12_m, G1_13_m, G1_23_m, + G2_11_m, G2_22_m, G2_33_m, G2_12_m, G2_13_m, G2_23_m, + G3_11_m, G3_22_m, G3_33_m, G3_12_m, G3_13_m, G3_23_m); +} diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 3543995702..5a6c484856 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -4,9 +4,11 @@ * given the contravariant metric tensor terms **************************************************************************/ +#include "bout/christoffel_symbols.hxx" #include "bout/coordinates_accessor.hxx" #include "bout/field3d.hxx" #include "bout/field_data.hxx" +#include "bout/g_values.hxx" #include #include #include @@ -21,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -37,14 +40,13 @@ #include #include #include -#include #include #include +#include #include #include -#include "invert3x3.hxx" #include "parallel/fci.hxx" #include "parallel/shiftedmetricinterp.hxx" @@ -266,45 +268,38 @@ Coordinates::Coordinates(Mesh* mesh, FieldMetric dx, FieldMetric dy, FieldMetric 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), - localoptions(nullptr), location(CELL_CENTRE) {} + : 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)), + transform(bout::utils::make_unique(*localmesh)), + contravariantMetricTensor(std::move(g11), std::move(g22), std::move(g33), + std::move(g12), std::move(g13), std::move(g23)), + covariantMetricTensor(std::move(g_11), std::move(g_22), std::move(g_33), + std::move(g_12), std::move(g_13), std::move(g_23)), + jacobian_cache(std::make_unique(std::move(J))), Bxy_(std::move(Bxy)) {} 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), nz(mesh->LocalNz), localmesh(mesh), localoptions(options), - location(CELL_CENTRE) { + : nz(mesh->LocalNz), localmesh(mesh), localoptions(options), location(CELL_CENTRE), + dx_(1., mesh), dy_(1., mesh), dz_(1., mesh), d1_dx_(mesh), d1_dy_(mesh), + d1_dz_(mesh), ShiftTorsion_(0.0, mesh), IntShiftTorsion_(0.0, mesh), + contravariantMetricTensor(1., 1., 1., 0, 0, 0, mesh), + covariantMetricTensor(1., 1., 1., 0, 0, 0, mesh), Bxy_(1., mesh) { readFromMesh(options, ""); - // Allow transform to fix things up - transform->loadParallelMetrics(this); + + if (transform != nullptr and not transform->canToFromFieldAligned()) { + // Read parallel metrics from gridfile for FCI + readParallelMetricComponents(); + } } 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), nz(mesh->LocalNz), localmesh(mesh), localoptions(options), - location(loc) { + : nz(mesh->LocalNz), localmesh(mesh), localoptions(options), location(loc), + dx_(1., mesh), dy_(1., mesh), dz_(1., mesh), d1_dx_(mesh), d1_dy_(mesh), + d1_dz_(mesh), ShiftTorsion_(0.0, mesh), IntShiftTorsion_(0.0, mesh), + contravariantMetricTensor(1., 1., 1., 0, 0, 0, mesh), + covariantMetricTensor(1., 1., 1., 0, 0, 0, mesh), Bxy_(1., mesh) { const std::string suffix = getLocationSuffix(location); @@ -313,9 +308,9 @@ Coordinates::Coordinates(Mesh* mesh, Options* options, const CELL_LOC loc, } else { // Interpolate fields from coords_in - if (isUniform(coords_in->dz)) { - dz = coords_in->dz; - dz.setLocation(location); + 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 " @@ -327,52 +322,39 @@ Coordinates::Coordinates(Mesh* mesh, Options* options, const CELL_LOC loc, return interpolateAndExtrapolate(f, location, true, true, false, transform.get()); }; - dx = interpField(coords_in->dx); - dy = interpField(coords_in->dy); + dx_ = interpField(coords_in->dx_); + dy_ = interpField(coords_in->dy_); // not really needed - we have used dz already ... - dz = interpField(coords_in->dz); - - // Diagonal components of metric tensor g^{ij} - g11 = interpField(coords_in->g11); - g22 = interpField(coords_in->g22); - g33 = interpField(coords_in->g33); - - // Off-diagonal elements. - g12 = interpField(coords_in->g12); - g13 = interpField(coords_in->g13); - g23 = interpField(coords_in->g23); - - // 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 = interpField(coords_in->g_11); - g_22 = interpField(coords_in->g_22); - g_33 = interpField(coords_in->g_33); - g_12 = interpField(coords_in->g_12); - g_13 = interpField(coords_in->g_13); - g_23 = interpField(coords_in->g_23); + dz_ = interpField(coords_in->dz_); + + setMetricTensor(coords_in->getContravariantMetricTensor(), + coords_in->getCovariantMetricTensor()); + + contravariantMetricTensor.map(interpField); + covariantMetricTensor.map(interpField); // Check input metrics checkContravariant(); checkCovariant(); - J = interpField(coords_in->J); - Bxy = interpField(coords_in->Bxy); + setJ(interpField(coords_in->J())); + setBxy(interpField(coords_in->Bxy())); - 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"); + 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 = interpField(coords_in->ShiftTorsion); + ShiftTorsion_ = interpField(coords_in->ShiftTorsion_); if (mesh->IncIntShear) { - IntShiftTorsion = interpField(coords_in->IntShiftTorsion); + IntShiftTorsion_ = interpField(coords_in->IntShiftTorsion_); + } + if (not transform->canToFromFieldAligned()) { + // Read parallel metrics from gridfile for FCI + readParallelMetricComponents(); } } - // Allow transform to fix things up - transform->loadParallelMetrics(this); } void Coordinates::readFromMesh(Options* options, const std::string& suffix) { @@ -425,6 +407,7 @@ void Coordinates::readFromMesh(Options* options, const std::string& suffix) { // Passing `field` in here twice is gross but ok because the second argument // is only used when interpolating, and we're not interpolating here fillGuards_impl(field, location, field, extrapolate_x, extrapolate_y); + return field; }; // Read the field, transform if required, and fill in the guards @@ -448,34 +431,27 @@ void Coordinates::readFromMesh(Options* options, const std::string& suffix) { // We can't use the helper functions here because in 3D we might (always?) // need to transform from field aligned -- which requires dz! So we have to // read it "plain" first... - localmesh->get(dz, "dz" + suffix, default_dz, false, location); + localmesh->get(dz_, "dz" + suffix, default_dz, false, location); } // ...then we can set the transform (required early for differentiation)... setParallelTransform(options); // ...and finally we can transform/interpolate/fill in guards - dz = interpolateAndExtrapolate(dz, location, extrapolate_x, extrapolate_y, false, - transform.get()); + setDz(interpolateAndExtrapolate(dz_, location, extrapolate_x, extrapolate_y, false, + transform.get())); // everything else from this point on can use our helper functions - dx = readAndFillGuards("dx", 1.0); + setDx(readAndFillGuards("dx", 1.0), localmesh->periodicX); - if (localmesh->periodicX) { - localmesh->communicate_no_slices(dx); - } - - dy = readAndFillGuards("dy", 1.0); + setDy(readAndFillGuards("dy", 1.0)); // Diagonal components of metric tensor g^{ij} (default to 1) - g11 = readAndFillGuards("g11", 1.0); - g22 = readAndFillGuards("g22", 1.0); - g33 = readAndFillGuards("g33", 1.0); - - // Off-diagonal elements. Default to 0 - g12 = readAndFillGuards("g12", 0.0); - g13 = readAndFillGuards("g13", 0.0); - g23 = readAndFillGuards("g23", 0.0); + contravariantMetricTensor = ContravariantMetricTensor{ + readAndFillGuards("g11", 1.0), readAndFillGuards("g22", 1.0), + readAndFillGuards("g33", 1.0), readAndFillGuards("g12", 0.0), + readAndFillGuards("g13", 0.0), readAndFillGuards("g23", 0.0), + }; // Check input metrics checkContravariant(); @@ -485,597 +461,375 @@ void Coordinates::readFromMesh(Options* options, const std::string& suffix) { 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), - 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 = readField("g_11", 1.0); - g_22 = readField("g_22", 1.0); - g_33 = readField("g_33", 1.0); - g_12 = readField("g_12", 0.0); - g_13 = readField("g_13", 0.0); - g_23 = readField("g_23", 0.0); - - output_warn.write("\tWARNING! Covariant components of metric tensor set manually. " - "Contravariant components NOT recalculated\n"); - } else { + // Check if any of the components are present, all of them are present + if (const bool all_present = + std::ranges::all_of(covariant_component_names, source_has_component); + std::ranges::any_of(covariant_component_names, source_has_component) + and all_present) { + covariantMetricTensor = CovariantMetricTensor{ + readAndFillGuards("g_11", 1.0), readAndFillGuards("g_22", 1.0), + readAndFillGuards("g_33", 1.0), readAndFillGuards("g_12", 0.0), + readAndFillGuards("g_13", 0.0), readAndFillGuards("g_23", 0.0), + }; + + output_warn.write("\tWARNING! Covariant components of metric tensor set manually. " + "Contravariant components NOT recalculated\n"); + } else { + if (not all_present) { 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") != 0) { - throw BoutException("Error in calcCovariant call"); - } - } - } else { - /// Calculate contravariant metric components if not found - if (calcCovariant("RGN_NOCORNERS") != 0) { - throw BoutException("Error in calcCovariant call"); } + covariantMetricTensor = contravariantMetricTensor.inverse("RGN_NOCORNERS", false); + + // More robust to extrapolate derived quantities directly, rather than + // deriving from extrapolated covariant metric components + covariantMetricTensor.map(fillGuards); } - // More robust to extrapolate derived quantities directly, rather than - // deriving from extrapolated covariant metric components - fillGuards(g_11); - fillGuards(g_22); - fillGuards(g_33); - fillGuards(g_12); - fillGuards(g_13); - fillGuards(g_23); // Check covariant metrics checkCovariant(); - // Calculate Jacobian and Bxy - jacobian(); - // Attempt to read J from the grid file - auto Jcalc = J; - if (localmesh->get(J, "J" + suffix, 0.0, false) != 0) { + auto Jcalc = J(); + FieldMetric J_temp{localmesh}; + if (localmesh->get(J_temp, "J" + suffix, 0.0, false) != 0) { output_warn.write( "\tWARNING: Jacobian 'J' not found. Calculating from metric tensor\n"); - J = Jcalc; + localmesh->communicate_no_slices(*jacobian_cache); } else { checkStaggeredGet(localmesh, "J", suffix); - J = ensuredUnaligned(J); - fillGuards(J); + *jacobian_cache = ensuredUnaligned(J_temp); + fillGuards(*jacobian_cache); // Compare calculated and loaded values - output_warn.write("\tMaximum difference in J is {:e}\n", max(abs(J - Jcalc))); - - localmesh->communicate_no_slices(J); + 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; + localmesh->communicate_no_slices(*jacobian_cache); } // 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 (localmesh->get(Bxy, "Bxy" + suffix, 0.0, false) != 0) { + const FieldMetric Bcalc = sqrt(g_22()) / J(); + if (localmesh->get(Bxy_, "Bxy" + suffix, 0.0, false) != 0) { output_warn.write("\tWARNING: Magnitude of B field 'Bxy' not found. Calculating from " "metric tensor\n"); - Bxy = Bcalc; + Bxy_ = interpolateAndExtrapolate(Bcalc, location, extrapolate_x, extrapolate_y, false, + transform.get()); + localmesh->communicate_no_slices(Bxy_); } else { checkStaggeredGet(localmesh, "Bxy", suffix); - Bxy = ensuredUnaligned(Bxy); - fillGuards(Bxy); - output_warn.write("\tMaximum difference in Bxy is {:e}\n", max(abs(Bxy - Bcalc))); + Bxy_ = ensuredUnaligned(Bxy_); + fillGuards(Bxy_); + output_warn.write("\tMaximum difference in Bxy is {:e}\n", max(abs(Bxy_ - Bcalc))); } // 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 (localmesh->get(ShiftTorsion, "ShiftTorsion" + suffix, 0.0, false) != 0) { - output_warn.write( - "\tWARNING: No Torsion specified for zShift. Derivatives may not be correct\n"); - ShiftTorsion = 0.0; + if (not localmesh->sourceHasVar("ShiftTorsion" + suffix)) { + output_warn.write("\tWARNING: No Torsion specified for zShift. " + "Derivatives may not be correct\n"); + } else { + ShiftTorsion_ = readAndFillGuards("ShiftTorsion", 0.0); } - fillGuards(ShiftTorsion); - - ////////////////////////////////////////////////////// if (localmesh->IncIntShear) { - if (localmesh->get(IntShiftTorsion, "IntShiftTorsion", 0.0, false) != 0) { + if (not localmesh->sourceHasVar("IntShiftTorsion" + suffix)) { output_warn.write("\tWARNING: No Integrated torsion specified\n"); + } else { + IntShiftTorsion_ = readAndFillGuards("IntShiftTorsion", 0.0); } - fillGuards(IntShiftTorsion); - } else { - // IntShiftTorsion will not be used, but set to zero to avoid uninitialized field - IntShiftTorsion = 0.; } - // Allow transform to fix things up - transform->loadParallelMetrics(this); } -void Coordinates::outputVars(Options& output_options) { - const Timer time("io"); - const std::string loc_string = - (location == CELL_CENTRE) ? "" : "_" + toString(location); +namespace bout { +// Get a unique name for a field based on the sign/magnitude of the offset +std::string parallelSliceFieldName(std::string_view field, int offset) { + using namespace std::string_view_literals; + const std::string_view direction = (offset > 0) ? "forward"sv : "backward"sv; + // We only have a suffix for parallel slices beyond the first + // This is for backwards compatibility + const std::string slice_suffix = + (std::abs(offset) > 1) ? fmt::format("_{}", std::abs(offset)) : ""; + return fmt::format("{}_{}{}", direction, field, slice_suffix); +}; +} // namespace bout - output_options["dx" + loc_string].force(dx, "Coordinates"); - output_options["dy" + loc_string].force(dy, "Coordinates"); - output_options["dz" + loc_string].force(dz, "Coordinates"); +namespace { +void load_parallel_metric_component(std::string_view name, bout::FieldMetric& component, + int offset) { + Mesh* mesh = component.getMesh(); + bout::FieldMetric tmp{mesh}; + const auto pname = bout::parallelSliceFieldName(name, offset); + if (mesh->get(tmp, pname, 0.0, false) != 0) { + throw BoutException("Could not read {:s} from grid file!\n" + " Fix it up with `zoidberg-update-parallel-metrics `", + pname); + } + if (!component.hasParallelSlices()) { + component.splitParallelSlices(); + component.disallowCalcParallelSlices(); + component.resetRegionParallel(true); + } + auto& pcom = component.ynext(offset); + pcom.allocate(); + BOUT_FOR(i, component.getRegion("RGN_NOBNDRY")) { pcom[i.yp(offset)] = tmp[i]; } +} +} // namespace - 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"); +void Coordinates::readParallelMetricComponents() { + if (not bout::build::use_metric_3d) { + return; + } + output_info.write("\tLoading parallel metrics\n"); + const FieldMetric JB0 = J() * Bxy(); + jacobian_cache->splitParallelSlices(); + jacobian_cache->disallowCalcParallelSlices(); + jacobian_cache->resetRegionParallel(true); + for (int i = 1; i <= localmesh->ystart; ++i) { + auto read_offset = [i](std::string_view name, FieldMetric& component) { + load_parallel_metric_component(name, component, -i); + load_parallel_metric_component(name, component, i); + }; - 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"); + read_offset("g_11", covariantMetricTensor.g11_m); + read_offset("g_22", covariantMetricTensor.g22_m); + read_offset("g_33", covariantMetricTensor.g33_m); + read_offset("g_13", covariantMetricTensor.g13_m); + read_offset("g11", contravariantMetricTensor.g11_m); + read_offset("g22", contravariantMetricTensor.g22_m); + read_offset("g33", contravariantMetricTensor.g33_m); + read_offset("g13", contravariantMetricTensor.g13_m); + read_offset("dy", dy_); + read_offset("Bxy", Bxy_); + + jacobian_cache->ynext(i).allocate(); + jacobian_cache->ynext(-i).allocate(); + BOUT_FOR(j, JB0.getRegion("RGN_NOBNDRY")) { + jacobian_cache->ynext(i)[j.yp(i)] = JB0[j] / Bxy_.ynext(i)[j.yp(i)]; + jacobian_cache->ynext(-i)[j.yp(-i)] = JB0[j] / Bxy_.ynext(-i)[j.yp(-i)]; + } + } +} - output_options["J" + loc_string].force(J, "Coordinates"); - output_options["Bxy" + loc_string].force(Bxy, "Coordinates"); +void Coordinates::outputVars(Options& output_options) { + const Timer time("io"); + const std::string loc_string = + (location == CELL_CENTRE) ? "" : "_" + toString(location); - 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["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["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"); + + if (g_values_cache != nullptr) { + // If we haven't used them yet, then presumably we don't actually need them, + // so let's not compute them now. + // Also, previously, we were explicitly setting the G-values to NaN for FCI + // instead of computing them (presumably because these are both difficult to + // compute accurately for FCI and unneeded in FCI models in practice). + 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); + invalidateCellGeometryCaches(); + invalidateAccessorCache(); + if (communicate) { + localmesh->communicate_no_slices(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); + invalidateCellGeometryCaches(); + invalidateAccessorCache(); + if (communicate) { + localmesh->communicate_no_slices(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); + zlength_cache.reset(); + invalidateCellGeometryCaches(); + invalidateAccessorCache(); + if (communicate) { + localmesh->communicate_no_slices(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 - - if (!g11.isFci()) { - 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); - - G1 = (DDX(J * g11) + DDY(J.asField3DParallel() * g12) + DDZ(J * g13)) / J; - G2 = (DDX(J * g12) + DDY(J.asField3DParallel() * g22) + DDZ(J * g23)) / J; - G3 = (DDX(J * g13) + DDY(J.asField3DParallel() * g23) + 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()); - } else { - G1_11 = G1_22 = G1_33 = G1_12 = G1_13 = G1_23 = - - G2_11 = G2_22 = G2_33 = G2_12 = G2_13 = G2_23 = + christoffel_symbols_cache.reset(); + g_values_cache.reset(); - G3_11 = G3_22 = G3_33 = G3_12 = G3_13 = G3_23 = + correctionForNonUniformMeshes(force_interpolate_from_centre); - G1 = G2 = G3 = BoutNaN; + if (location == CELL_CENTRE && recalculate_staggered) { + // Re-calculate interpolated Coordinates at staggered locations + localmesh->recalculateStaggeredCoordinates(); } - ////////////////////////////////////////////////////// - /// Non-uniform meshes. Need to use DDX, DDY + zlength_cache.reset(); + Grad2_par2_DDY_invSgCache.clear(); + invSgCache.reset(); + invalidateCellGeometryCaches(); + invalidateAccessorCache(); +} - OPTION(Options::getRoot(), non_uniform, true); +void Coordinates::correctionForNonUniformMeshes(bool force_interpolate_from_centre) { + OPTION(Options::getRoot(), non_uniform_, true); - Coordinates::FieldMetric d2x(localmesh), d2y(localmesh), - d2z(localmesh); // d^2 x / d i^2 + FieldMetric d2x(localmesh); + FieldMetric d2y(localmesh); // Read correction for non-uniform meshes - std::string suffix = getLocationSuffix(location); + const std::string suffix = getLocationSuffix(location); + + auto extrapolate_x = true; + auto extrapolate_y = true; 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(); + extrapolate_x = not localmesh->sourceHasXBoundaryGuards(); + 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(FieldMetric{1. / dx}); // d/di(1/dx) + 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(FieldMetric{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()); + 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); - } + 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.asField3DParallel()); // d/di(1/dy) + 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().asField3DParallel()); // 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()); + 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); - } + 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(FieldMetric{1. / dz}); - localmesh->communicate_no_slices(d1_dz); - d1_dz = - interpolateAndExtrapolate(d1_dz, location, true, true, true, transform.get()); + if (bout::build::use_metric_3d) { + FieldMetric d2z(localmesh); // d^2 x / d i^2 + if (localmesh->get(d2z, "d2z" + suffix, 0.0, false, location) != 0) { + output_warn.write("\tWARNING: differencing quantity 'd2z' not found. " + "Calculating from dz\n"); + d1_dz_ = bout::derivatives::index::DDZ(FieldMetric{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); + 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(FieldMetric{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(FieldMetric{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(FieldMetric{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()); - - d1_dz = -d2z / (dz * dz); - } -#else - d1_dz = 0; -#endif - } - localmesh->communicate_no_slices(d1_dx, d1_dy, d1_dz); - - if (location == CELL_CENTRE && recalculate_staggered) { - // Re-calculate interpolated Coordinates at staggered locations - localmesh->recalculateStaggeredCoordinates(); - } - - // Invalidate and recalculate cached variables and any accessor - zlength_cache.reset(); - Grad2_par2_DDY_invSgCache.clear(); - invSgCache.reset(); - CoordinatesAccessor::clear(this); - - _g_22_ylow.reset(); - _g_22_yhigh.reset(); - _cell_area_xlow.reset(); - _cell_area_xhigh.reset(); - _cell_area_ylow.reset(); - _cell_area_yhigh.reset(); - _cell_area_zlow.reset(); - _cell_area_zhigh.reset(); - _cell_volume.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))); - - output_info.write("\tLocal maximum error in off-diagonal inversion is {:e}\n", maxerr); - - 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); - - g12[i] = a(0, 1); - g13[i] = a(0, 2); - g23[i] = a(1, 2); + d1_dz_ = 0; } - BoutReal maxerr; - maxerr = BOUTMAX(max(abs((g_11 * g11 + g_12 * g12 + g_13 * g13) - 1)), - max(abs((g_12 * g12 + g_22 * g22 + g_23 * g23) - 1)), - max(abs((g_13 * g13 + g_23 * g23 + g_33 * g33) - 1))); - - output_info.write("\tMaximum error in diagonal inversion is {:e}\n", maxerr); - - 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; + localmesh->communicate_no_slices(d1_dx_, d1_dy_, d1_dz_); } -int Coordinates::jacobian() { - +Coordinates::FieldMetric Coordinates::recalculateJacobian() const { // calculate Jacobian using g^-1 = det[g^ij], J = sqrt(g) + const FieldMetric g_matrix = g11() * g22() * g33() + 2.0 * g12() * g13() * g23() + - g11() * g23() * g23() - g22() * g13() * g13() + - g33() * g12() * g12(); - const bool extrapolate_x = not localmesh->sourceHasXBoundaryGuards(); - const bool extrapolate_y = not localmesh->sourceHasYBoundaryGuards(); - - const FieldMetric g = g11 * g22 * g33 + 2.0 * g12 * g13 * g23 - g11 * g23 * g23 - - g22 * g13 * g13 - g33 * g12 * g12; + bout::checkPositive(g_matrix, "The determinant of g^ij", "RGN_NOBNDRY"); - // Check that g is positive - bout::checkPositive(g, "The determinant of g^ij", "RGN_NOBNDRY"); - - J = 1. / sqrt(g); - // More robust to extrapolate derived quantities directly, rather than - // deriving from extrapolated covariant metric components - J = interpolateAndExtrapolate(J, location, extrapolate_x, extrapolate_y, false, - transform.get()); - - Bxy = sqrt(g_22) / J; - Bxy = interpolateAndExtrapolate(Bxy, location, extrapolate_x, extrapolate_y, false, - transform.get()); + return 1. / sqrt(g_matrix); +} - return 0; +Coordinates::FieldMetric Coordinates::recalculateBxy() const { + return sqrt(g_22()) / J(); } namespace { // Utility function for fixing up guard cells of zShift void fixZShiftGuards(Field2D& zShift) { - auto localmesh = zShift.getMesh(); + auto* localmesh = zShift.getMesh(); // extrapolate into boundary guard cells if necessary zShift = interpolateAndExtrapolate(zShift, zShift.getLocation(), @@ -1174,548 +928,149 @@ 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); - + transform = bout::utils::make_unique(*localmesh, dy(), fci_zperiodic, + ptoptions); } else { - throw BoutException(_("Unrecognised paralleltransform option.\n" - "Valid choices are 'identity', 'shifted', 'fci'")); + throw BoutException(_f("Unrecognised paralleltransform option '{}'.\n" + "Valid choices are 'identity', 'shifted', 'fci'"), + ptstr); } } -/******************************************************************************* - * Operators - * - *******************************************************************************/ - -Coordinates::FieldMetric Coordinates::DDX(const Field2D& f, CELL_LOC loc, - const std::string& method, - const std::string& region) { - ASSERT1(location == loc || loc == CELL_DEFAULT); - 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) { - - auto result = bout::derivatives::index::DDX(f, outloc, method, region); - result /= dx; - - if (f.getMesh()->IncIntShear) { - // Using BOUT-06 style shifting - result += IntShiftTorsion * DDZ(f, outloc, method, region); +const ChristoffelSymbols& Coordinates::christoffel_symbols() const { + BOUT_OMP_SAFE(critical(christoffel_symbols_cache)) + { + 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 result; -}; - -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 *christoffel_symbols_cache; } -Field3D Coordinates::DDY(const Field3DParallel& f, CELL_LOC outloc, - const std::string& method, const std::string& region) const { - 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)) { - ASSERT1(location == loc || loc == CELL_DEFAULT); - ASSERT1(f.getMesh() == localmesh); - if (loc == CELL_DEFAULT) { - loc = f.getLocation(); +GValues& Coordinates::g_values() const { + BOUT_OMP_SAFE(critical(g_values_cache)) + { + 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 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; -}; - -///////////////////////////////////////////////////////// -// Parallel gradient - -Coordinates::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())); - - return DDY(var) * invSg(); + return *g_values_cache; } -Field3D Coordinates::Grad_par(const Field3DParallel& var, CELL_LOC outloc, - const std::string& method) { - - ASSERT1(location == outloc || outloc == CELL_DEFAULT); - - return ::DDY(var, outloc, method) * invSg(); -} - -///////////////////////////////////////////////////////// -// 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)) { - ASSERT1(location == outloc || (outloc == CELL_DEFAULT && location == f.getLocation())); - - return VDDY(v, f) * invSg(); -} - -Field3D Coordinates::Vpar_Grad_par(const Field3D& v, const Field3DParallel& f, - CELL_LOC outloc, const std::string& method) { - ASSERT1(location == outloc || outloc == CELL_DEFAULT); - - return VDDY(v, f, outloc, method) * invSg(); -} - -///////////////////////////////////////////////////////// -// Parallel divergence - -Coordinates::FieldMetric Coordinates::Div_par(const Field2D& f, CELL_LOC outloc, - const std::string& method) { - - ASSERT1(location == outloc || outloc == CELL_DEFAULT); - - // Need Bxy at location of f, which might be different from location of this - // Coordinates object - auto Bxy_floc = f.getCoordinates()->Bxy; - - return Bxy * Grad_par(FieldMetric{f / Bxy_floc}, outloc, method); -} - -Field3D Coordinates::Div_par(const Field3DParallel& f, CELL_LOC outloc, - const std::string& method) { - - ASSERT1(location == outloc || outloc == CELL_DEFAULT); - - // Need Bxy at location of f, which might be different from location of this - // Coordinates object - const auto& Bxy_floc = f.getCoordinates()->Bxy; - - return Bxy * Grad_par(f / Bxy_floc, outloc, method); -} - -///////////////////////////////////////////////////////// -// second parallel derivative (b dot Grad)(b dot Grad) -// Note: For parallel Laplacian use Laplace_par - -Coordinates::FieldMetric Coordinates::Grad2_par2(const Field2D& f, CELL_LOC outloc, - const std::string& method) { - - 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; - - return result; -} - -Field3D Coordinates::Grad2_par2(const Field3DParallel& f, CELL_LOC outloc, - const std::string& method) { - - if (outloc == CELL_DEFAULT) { - outloc = f.getLocation(); +const Coordinates::FieldMetric& Coordinates::invSg() const { + BOUT_OMP_SAFE(critical(invSg_cache)) + { + if (invSgCache == nullptr) { + auto ptr = std::make_unique(); + (*ptr) = 1.0 / sqrt(g_22()); + invSgCache = std::move(ptr); + } } - ASSERT1(location == outloc); - - Field3D result = ::DDY(f, outloc, method); - - Field3D r2 = D2DY2(f, outloc, method) / g_22; - - result = Grad2_par2_DDY_invSg(outloc, method) * result + r2; - - ASSERT2(result.getLocation() == outloc); - - return result; -} - -///////////////////////////////////////////////////////// -// perpendicular Laplacian operator - -#include // Delp2 uses same coefficients as inversion code - -Coordinates::FieldMetric Coordinates::Delp2(const Field2D& f, CELL_LOC outloc, - bool UNUSED(useFFT)) { - - ASSERT1(location == outloc || outloc == CELL_DEFAULT); - - auto result = G1 * DDX(f, outloc) + g11 * D2DX2(f, outloc); - - return result; + return *invSgCache; } -Field3D Coordinates::Delp2(const Field3D& f, CELL_LOC outloc, bool useFFT) { - - if (outloc == CELL_DEFAULT) { - outloc = f.getLocation(); - } - - ASSERT1(location == outloc); - ASSERT1(f.getLocation() == outloc); - - if (localmesh->GlobalNx == 1 && localmesh->GlobalNz == 1) { - // copy mesh, location, etc - return f * 0; - } - ASSERT2(localmesh->xstart > 0); // Need at least one guard cell - - Field3D result{emptyFrom(f).setLocation(outloc)}; - - if (useFFT and not bout::build::use_metric_3d and localmesh->getNZPE() == 1) { - int ncz = localmesh->LocalNz; - - // Allocate memory - auto ft = Matrix(localmesh->LocalNx, ncz / 2 + 1); - auto delft = Matrix(localmesh->LocalNx, ncz / 2 + 1); - - // Loop over y indices - // Note: should not include y-guard or y-boundary points here as that would - // use values from corner cells in dx, which may not be initialised. - for (int jy = localmesh->ystart; jy <= localmesh->yend; jy++) { - - // Take forward FFT - - for (int jx = 0; jx < localmesh->LocalNx; jx++) { - rfft(&f(jx, jy, 0), ncz, &ft(jx, 0)); - } - - // Loop over kz - for (int jz = 0; jz <= ncz / 2; jz++) { - - // No smoothing in the x direction - for (int jx = localmesh->xstart; jx <= localmesh->xend; jx++) { - // Perform x derivative - - dcomplex a, b, c; - laplace_tridag_coefs(jx, jy, jz, a, b, c, nullptr, nullptr, outloc); - - delft(jx, jz) = a * ft(jx - 1, jz) + b * ft(jx, jz) + c * ft(jx + 1, jz); - } +const Coordinates::FieldMetric& +Coordinates::Grad2_par2_DDY_invSg(CELL_LOC outloc, const std::string& method) const { + const FieldMetric* result{nullptr}; + BOUT_OMP_SAFE(critical(Grad2_par2_DDY_invSg_cache)) + { + if (auto search = Grad2_par2_DDY_invSgCache.find(method); + search != Grad2_par2_DDY_invSgCache.end()) { + result = search->second.get(); + } else { + if (invSgCache == nullptr) { + auto ptr = std::make_unique(); + (*ptr) = 1.0 / sqrt(g_22()); + invSgCache = std::move(ptr); } - // Reverse FFT - for (int jx = localmesh->xstart; jx <= localmesh->xend; jx++) { + // Communicate to get parallel slices + localmesh->communicate(*invSgCache); + invSgCache->applyParallelBoundary("parallel_neumann_o2"); - irfft(&delft(jx, 0), ncz, &result(jx, jy, 0)); - } + auto ptr = std::make_unique(); + *ptr = DDY(*invSgCache, outloc, method) * (*invSgCache); + result = ptr.get(); + Grad2_par2_DDY_invSgCache[method] = std::move(ptr); } - } else { - 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); - - return result; -} - -FieldPerp Coordinates::Delp2(const FieldPerp& f, CELL_LOC outloc, bool useFFT) { - - if (outloc == CELL_DEFAULT) { - outloc = f.getLocation(); - } - - ASSERT1(location == outloc); - ASSERT1(f.getLocation() == outloc); - - if (localmesh->GlobalNx == 1 && localmesh->GlobalNz == 1) { - // copy mesh, location, etc - return f * 0; } - ASSERT2(localmesh->xstart > 0); // Need at least one guard cell - - FieldPerp result{emptyFrom(f).setLocation(outloc)}; - - int jy = f.getIndex(); - result.setIndex(jy); - - if (useFFT and localmesh->getNZPE() == 1) { - int ncz = localmesh->LocalNz; - - // Allocate memory - auto ft = Matrix(localmesh->LocalNx, ncz / 2 + 1); - auto delft = Matrix(localmesh->LocalNx, ncz / 2 + 1); - - // Take forward FFT - for (int jx = 0; jx < localmesh->LocalNx; jx++) { - rfft(&f(jx, 0), ncz, &ft(jx, 0)); - } - - // Loop over kz - for (int jz = 0; jz <= ncz / 2; jz++) { - - // No smoothing in the x direction - for (int jx = localmesh->xstart; jx <= localmesh->xend; jx++) { - // Perform x derivative - - dcomplex a, b, c; - laplace_tridag_coefs(jx, jy, jz, a, b, c); - - delft(jx, jz) = a * ft(jx - 1, jz) + b * ft(jx, jz) + c * ft(jx + 1, jz); - } - } - - // Reverse FFT - for (int jx = localmesh->xstart; jx <= localmesh->xend; jx++) { - irfft(&delft(jx, 0), ncz, &result(jx, 0)); - } - - } else { - throw BoutException("Non-fourier Delp2 not currently implented for FieldPerp."); - // Would be the following but don't have standard derivative operators for FieldPerps - // yet - // result = G1 * ::DDX(f, outloc) + G3 * ::DDZ(f, outloc) + g11 * ::D2DX2(f, outloc) - // + g33 * ::D2DZ2(f, outloc) + 2 * g13 * ::D2DXDZ(f, outloc); - }; - - return result; -} - -Coordinates::FieldMetric Coordinates::Laplace_par(const Field2D& f, CELL_LOC outloc) { - ASSERT1(location == outloc || outloc == CELL_DEFAULT); - return D2DY2(f, outloc) / g_22 - + DDY(FieldMetric{J / g_22}, outloc) * DDY(f, outloc) / J; + return *result; } -Field3D Coordinates::Laplace_par(const Field3DParallel& f, CELL_LOC outloc) { - ASSERT1(location == outloc || outloc == CELL_DEFAULT); - return D2DY2(f, outloc) / g_22 - + DDY(J.asField3DParallel() / g_22, outloc) * ::DDY(f, outloc) / J; -} - -// Full Laplacian operator on scalar field - -Coordinates::FieldMetric Coordinates::Laplace(const Field2D& f, CELL_LOC outloc, - const std::string& dfdy_boundary_conditions, - const std::string& dfdy_dy_region) { +void Coordinates::checkCovariant() { covariantMetricTensor.check(localmesh->ystart); } - 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; +void Coordinates::checkContravariant() { + contravariantMetricTensor.check(localmesh->ystart); } -Field3D Coordinates::Laplace(const Field3DParallel& f, CELL_LOC outloc, - const std::string& dfdy_boundary_conditions, - const std::string& dfdy_dy_region) { - - 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; +void Coordinates::invalidateCellGeometryCaches() { + _g_22_ylow.reset(); + _g_22_yhigh.reset(); + _cell_area_xlow.reset(); + _cell_area_xhigh.reset(); + _cell_area_ylow.reset(); + _cell_area_yhigh.reset(); + _cell_area_zlow.reset(); + _cell_area_zhigh.reset(); + _cell_volume.reset(); } -// 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) { - -#if not(BOUT_USE_METRIC_3D) - Field2D result; - result.allocate(); - for (auto i : result.getRegion(RGN_NOBNDRY)) { - result[i] = 0.; - - // 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_value = - 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_value = - 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_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]); - 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_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]); - result[i] += lower_y_value * (f[i.ym()] - f[i]); - } +void Coordinates::invalidateAccessorCache() const { CoordinatesAccessor::clear(this); } - return result; -#else - throw BoutException("Coordinates::Laplace_perpXY for 3D metric not implemented"); -#endif -} - -const Coordinates::FieldMetric& Coordinates::invSg() const { - if (invSgCache == nullptr) { - auto ptr = std::make_unique(); - (*ptr) = 1.0 / sqrt(g_22); - invSgCache = std::move(ptr); - } - return *invSgCache; +void Coordinates::invalidateJacobianCaches() { + g_values_cache.reset(); + invalidateCellGeometryCaches(); + invalidateAccessorCache(); } -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; - } - invSg(); - - // Communicate to get parallel slices - localmesh->communicate(*invSgCache); - invSgCache->applyParallelBoundary("parallel_neumann_o2"); - - // cache - auto ptr = std::make_unique(); - *ptr = DDY(*invSgCache, outloc, method) * invSg(); - Grad2_par2_DDY_invSgCache[method] = std::move(ptr); - return *Grad2_par2_DDY_invSgCache[method]; +void Coordinates::invalidateMetricCaches() { + christoffel_symbols_cache.reset(); + g_values_cache.reset(); + Grad2_par2_DDY_invSgCache.clear(); + invSgCache.reset(); + jacobian_cache.reset(); + invalidateCellGeometryCaches(); + invalidateAccessorCache(); } -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)); - } - } - } - - // 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)); - } +const Coordinates::FieldMetric& Coordinates::J() const { + BOUT_OMP_SAFE(critical(jacobian_cache)) + { + if (jacobian_cache == nullptr) { + jacobian_cache = std::make_unique(recalculateJacobian()); } } + return *jacobian_cache; } -void Coordinates::checkContravariant() { - // Diagonal metric components should be finite - bout::checkFinite(g11, "g11", "RGN_NOCORNERS"); - bout::checkFinite(g22, "g22", "RGN_NOCORNERS"); - bout::checkFinite(g33, "g33", "RGN_NOCORNERS"); - if (g11.hasParallelSlices() && &g11.ynext(1) != &g11) { - for (int dy = 1; dy <= localmesh->ystart; ++dy) { - for (const auto sign : {1, -1}) { - bout::checkFinite(g11.ynext(sign * dy), "g11.ynext", - fmt::format("RGN_YPAR_{:+d}", sign * dy)); - bout::checkFinite(g22.ynext(sign * dy), "g22.ynext", - fmt::format("RGN_YPAR_{:+d}", sign * dy)); - bout::checkFinite(g33.ynext(sign * dy), "g33.ynext", - fmt::format("RGN_YPAR_{:+d}", sign * dy)); - } - } - } - // Diagonal metric components should be positive - bout::checkPositive(g11, "g11", "RGN_NOCORNERS"); - bout::checkPositive(g22, "g22", "RGN_NOCORNERS"); - bout::checkPositive(g33, "g33", "RGN_NOCORNERS"); - if (g11.hasParallelSlices() && &g11.ynext(1) != &g11) { - for (int dy = 1; dy <= localmesh->ystart; ++dy) { - for (const auto sign : {1, -1}) { - bout::checkPositive(g11.ynext(sign * dy), "g11.ynext", - fmt::format("RGN_YPAR_{:+d}", sign * dy)); - bout::checkPositive(g22.ynext(sign * dy), "g22.ynext", - fmt::format("RGN_YPAR_{:+d}", sign * dy)); - bout::checkPositive(g33.ynext(sign * dy), "g33.ynext", - fmt::format("RGN_YPAR_{:+d}", sign * dy)); - } - } - } +void Coordinates::setJ(const FieldMetric& J, const bool communicate) { + bout::checkFinite(J, "J", "RGN_NOCORNERS"); + bout::checkPositive(J, "J", "RGN_NOCORNERS"); - // 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)); - } - } + //TODO: Calculate J and check value is close + invalidateJacobianCaches(); + jacobian_cache = std::make_unique(J); + if (communicate) { + localmesh->communicate_no_slices(*jacobian_cache); } } @@ -1726,18 +1081,16 @@ const Coordinates::FieldMetric& Coordinates::g_22_ylow() const { BOUT_OMP_SAFE(critical) { if (!_g_22_ylow.has_value()) { - _g_22_ylow.emplace(emptyFrom(g_22)); - //_g_22_ylow->setLocation(CELL_YLOW); - auto* mesh = Bxy.getMesh(); - if (Bxy.isFci()) { - if (mesh->get(_g_22_ylow.value(), "g_22_cell_ylow", 0.0, false) != 0) { + _g_22_ylow.emplace(emptyFrom(g_22())); + if (Bxy().isFci()) { + if (localmesh->get(_g_22_ylow.value(), "g_22_cell_ylow", 0.0, false) != 0) { throw BoutException("The grid file does not contain `g_22_cell_ylow`."); } } else { - ASSERT0(mesh->ystart > 0); - BOUT_FOR(i, g_22.getRegion("RGN_NOY")) { + ASSERT0(localmesh->ystart > 0); + BOUT_FOR(i, g_22().getRegion("RGN_NOY")) { _g_22_ylow.value()[i] = - SQ(0.5 * (std::sqrt(g_22[i]) + std::sqrt(g_22[i.ym()]))); + SQ(0.5 * (std::sqrt(g_22()[i]) + std::sqrt(g_22()[i.ym()]))); } } } @@ -1752,17 +1105,16 @@ const Coordinates::FieldMetric& Coordinates::g_22_yhigh() const { BOUT_OMP_SAFE(critical) { if (!_g_22_yhigh.has_value()) { - _g_22_yhigh.emplace(emptyFrom(g_22)); - auto* mesh = Bxy.getMesh(); - if (Bxy.isFci()) { - if (mesh->get(_g_22_yhigh.value(), "g_22_cell_yhigh", 0.0, false) != 0) { + _g_22_yhigh.emplace(emptyFrom(g_22())); + if (Bxy().isFci()) { + if (localmesh->get(_g_22_yhigh.value(), "g_22_cell_yhigh", 0.0, false) != 0) { throw BoutException("The grid file does not contain `g_22_cell_yhigh`."); } } else { - ASSERT0(mesh->ystart > 0); - BOUT_FOR(i, g_22.getRegion("RGN_NOY")) { + ASSERT0(localmesh->ystart > 0); + BOUT_FOR(i, g_22().getRegion("RGN_NOY")) { _g_22_yhigh.value()[i] = - SQ(0.5 * (std::sqrt(g_22[i]) + std::sqrt(g_22[i.yp()]))); + SQ(0.5 * (std::sqrt(g_22()[i]) + std::sqrt(g_22()[i.yp()]))); } } } @@ -1774,13 +1126,12 @@ void Coordinates::_compute_cell_area_x() const { BOUT_OMP_SAFE(critical) { if (!_cell_area_xlow.has_value()) { - const FieldMetric area_centre = J / sqrt(g_11) * dy * dz; + const FieldMetric area_centre = J() / sqrt(g_11()) * dy_ * dz_; _cell_area_xlow.emplace(emptyFrom(area_centre)); _cell_area_xhigh.emplace(emptyFrom(area_centre)); // We cannot setLocation, as that would trigger the computation of staggered // metrics. - auto* mesh = Bxy.getMesh(); - ASSERT0(mesh->xstart > 0); + ASSERT0(localmesh->xstart > 0); BOUT_FOR(i, area_centre.getRegion("RGN_NOX")) { (*_cell_area_xlow)[i] = 0.5 * (area_centre[i] + area_centre[i.xm()]); (*_cell_area_xhigh)[i] = 0.5 * (area_centre[i] + area_centre[i.xp()]); @@ -1793,48 +1144,47 @@ void Coordinates::_compute_cell_area_y() const { BOUT_OMP_SAFE(critical) { if (!_cell_area_ylow.has_value()) { - auto* mesh = Bxy.getMesh(); - if (g_11.isFci()) { - const FieldMetric jxz_centre = J / sqrt(g_22); + if (g_11().isFci()) { + const FieldMetric jxz_centre = J() / sqrt(g_22()); auto jxz_ylow = emptyFrom(jxz_centre); auto jxz_yhigh = emptyFrom(jxz_centre); auto By_c = emptyFrom(jxz_centre); auto By_h = emptyFrom(jxz_yhigh); auto By_l = emptyFrom(jxz_ylow); - if (mesh->get(By_c, "By", 0.0, false, CELL_CENTRE) != 0) { + if (localmesh->get(By_c, "By", 0.0, false, CELL_CENTRE) != 0) { throw BoutException("The grid file does not contain `By`."); } - if (mesh->get(By_l, "By_cell_ylow", 0.0, false) != 0) { + if (localmesh->get(By_l, "By_cell_ylow", 0.0, false) != 0) { throw BoutException("The grid file does not contain `By_cell_ylow`."); } - if (mesh->get(By_h, "By_cell_yhigh", 0.0, false) != 0) { + if (localmesh->get(By_h, "By_cell_yhigh", 0.0, false) != 0) { throw BoutException("The grid file does not contain `By_cell_yhigh`."); } BOUT_FOR(i, By_c.getRegion("RGN_NOY")) { jxz_ylow[i] = By_c[i] / By_l[i] * jxz_centre[i]; jxz_yhigh[i] = By_c[i] / By_h[i] * jxz_centre[i]; } - ASSERT3(isUniform(dx, true, "RGN_ALL")); - ASSERT2(isUniform(dx, false, "RGN_ALL")); - ASSERT3(isUniform(dz, true, "RGN_ALL")); - ASSERT2(isUniform(dz, false, "RGN_ALL")); - _cell_area_ylow.emplace(jxz_ylow * dx * dz); - _cell_area_yhigh.emplace(jxz_yhigh * dx * dz); + ASSERT3(isUniform(dx_, true, "RGN_ALL")); + ASSERT2(isUniform(dx_, false, "RGN_ALL")); + ASSERT3(isUniform(dz_, true, "RGN_ALL")); + ASSERT2(isUniform(dz_, false, "RGN_ALL")); + _cell_area_ylow.emplace(jxz_ylow * dx_ * dz_); + _cell_area_yhigh.emplace(jxz_yhigh * dx_ * dz_); } else { // Field aligned - const FieldMetric area_centre = J / sqrt(g_22) * dx * dz; + const FieldMetric area_centre = J() / sqrt(g_22()) * dx_ * dz_; _cell_area_ylow.emplace(emptyFrom(area_centre)); _cell_area_yhigh.emplace(emptyFrom(area_centre)); // We cannot setLocation, as that would trigger the computation of staggered // metrics. - BOUT_FOR(i, mesh->getRegion("RGN_ALL")) { + BOUT_FOR(i, localmesh->getRegion("RGN_ALL")) { if (i.y() > 0) { (*_cell_area_ylow)[i] = 0.5 * (area_centre[i] + area_centre[i.ym()]); } else { (*_cell_area_ylow)[i] = BoutNaN; } - if (i.y() < mesh->LocalNy - 1) { + if (i.y() < localmesh->LocalNy - 1) { (*_cell_area_yhigh)[i] = 0.5 * (area_centre[i] + area_centre[i.yp()]); } else { (*_cell_area_yhigh)[i] = BoutNaN; @@ -1849,7 +1199,7 @@ void Coordinates::_compute_cell_area_z() const { BOUT_OMP_SAFE(critical) { if (!_cell_area_zlow.has_value()) { - const FieldMetric area_centre = J / sqrt(g_33) * dx * dy; + const FieldMetric area_centre = J() / sqrt(g_33()) * dx_ * dy_; _cell_area_zlow.emplace(emptyFrom(area_centre)); _cell_area_zhigh.emplace(emptyFrom(area_centre)); // We cannot setLocation, as that would trigger the computation of staggered @@ -1866,7 +1216,7 @@ void Coordinates::_compute_cell_volume() const { BOUT_OMP_SAFE(critical) { if (!_cell_volume.has_value()) { - _cell_volume.emplace(J * dx * dy * dz); + _cell_volume.emplace(*jacobian_cache * dx_ * dy_ * dz_); } } } @@ -1874,3 +1224,59 @@ void Coordinates::_compute_cell_volume() const { std::shared_ptr Coordinates::makeYBoundary(YBndryType type) const { return std::make_shared(type, localoptions, *localmesh); } + +void Coordinates::setBxy(FieldMetric Bxy, const bool communicate) { + //TODO: Calculate Bxy and check value is close + Bxy_ = std::move(Bxy); + _g_22_ylow.reset(); + _g_22_yhigh.reset(); + invalidateAccessorCache(); + if (communicate) { + localmesh->communicate_no_slices(Bxy_); + } +} + +void Coordinates::setContravariantMetricTensor( + const ContravariantMetricTensor& metric_tensor, const std::string& region, + bool recalculate_staggered, bool force_interpolate_from_centre) { + contravariantMetricTensor = metric_tensor; + covariantMetricTensor = contravariantMetricTensor.inverse(region); + invalidateMetricCaches(); + setJ(recalculateJacobian()); + setBxy(recalculateBxy()); + 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 = metric_tensor; + contravariantMetricTensor = covariantMetricTensor.inverse(region); + invalidateMetricCaches(); + setJ(recalculateJacobian()); + setBxy(recalculateBxy()); + recalculateAndReset(recalculate_staggered, force_interpolate_from_centre); +} + +void Coordinates::setMetricTensor( + const ContravariantMetricTensor& contravariant_metric_tensor, + const CovariantMetricTensor& covariant_metric_tensor) { + contravariantMetricTensor = contravariant_metric_tensor; + covariantMetricTensor = covariant_metric_tensor; + invalidateMetricCaches(); + setJ(recalculateJacobian()); + setBxy(recalculateBxy()); +} + +void Coordinates::communicateMetricTensor() { + contravariantMetricTensor.communicate(); + covariantMetricTensor.communicate(); +} + +void Coordinates::communicateDz() { localmesh->communicate(dz_); } + +void Coordinates::splitBxyParallelSlices() { + Bxy_.splitParallelSlices(); + Bxy_.yup() = Bxy_.ydown() = Bxy_; +} diff --git a/src/mesh/coordinates_accessor.cxx b/src/mesh/coordinates_accessor.cxx index efc27e9715..2c9eaf6de9 100644 --- a/src/mesh/coordinates_accessor.cxx +++ b/src/mesh/coordinates_accessor.cxx @@ -18,7 +18,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(); + const Mesh* mesh = coords->dx().getMesh(); mesh_nz = mesh->LocalNz; auto search = coords_store.find(coords); @@ -41,9 +41,11 @@ 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) \ - if (coords->symbol.isAllocated()) \ - data[stripe_size * ind.ind + static_cast(Offset::symbol)] = coords->symbol[ind]; +#define COPY_STRIPE1(symbol) \ + if (coords->symbol().isAllocated()) { \ + data[stripe_size * ind.ind + static_cast(Offset::symbol)] = \ + coords->symbol()[ind]; \ + } // Implement copy for each argument #define COPY_STRIPE(...) \ @@ -53,19 +55,21 @@ CoordinatesAccessor::CoordinatesAccessor(const Coordinates* coords) { // Iterate over all points in the field // Note this could be 2D or 3D, depending on FieldMetric type - for (const auto& ind : coords->dx.getRegion("RGN_ALL")) { + for (const auto& ind : coords->dx().getRegion("RGN_ALL")) { COPY_STRIPE(dx, dy, dz); COPY_STRIPE(d1_dx, d1_dy, d1_dz); COPY_STRIPE(J); - if (coords->Bxy.isAllocated()) { - data[stripe_size * ind.ind + static_cast(Offset::B)] = coords->Bxy[ind]; - if (coords->Bxy.yup().isAllocated()) + if (coords->Bxy().isAllocated()) { + data[(stripe_size * ind.ind) + static_cast(Offset::B)] = coords->Bxy()[ind]; + if (coords->Bxy().yup().isAllocated()) { data[stripe_size * ind.ind + static_cast(Offset::Byup)] = - coords->Bxy.yup()[ind]; - if (coords->Bxy.ydown().isAllocated()) + coords->Bxy().yup()[ind]; + } + if (coords->Bxy().ydown().isAllocated()) { data[stripe_size * ind.ind + static_cast(Offset::Bydown)] = - coords->Bxy.ydown()[ind]; + coords->Bxy().ydown()[ind]; + } } COPY_STRIPE(G1, G3); diff --git a/src/mesh/difops.cxx b/src/mesh/difops.cxx index 8ecd9d64ff..433316a793 100644 --- a/src/mesh/difops.cxx +++ b/src/mesh/difops.cxx @@ -23,8 +23,10 @@ * **************************************************************************/ +#include "bout/build_config.hxx" #include "bout/build_defines.hxx" - +#include "bout/dcomplex.hxx" +#include "bout/metric_tensor.hxx" #include #include #include @@ -35,40 +37,29 @@ #include #include #include +#include +#include // Delp2 uses same coefficients as inversion code #include #include #include -#include -#include - -#include // Delp2 uses same coefficients as inversion code - -#include #include +#include #include +#include /******************************************************************************* * Grad_par * The parallel derivative along unperturbed B-field *******************************************************************************/ -Coordinates::FieldMetric Grad_par(const Field2D& var, CELL_LOC outloc, - const std::string& method) { - return var.getCoordinates(outloc)->Grad_par(var, outloc, method); -} - -Coordinates::FieldMetric Grad_par(const Field2D& var, const std::string& method, - CELL_LOC outloc) { - return var.getCoordinates(outloc)->Grad_par(var, outloc, method); +bout::FieldMetric Grad_par(const Field2D& var, CELL_LOC outloc, + const std::string& method) { + return DDY(var, outloc, method) * var.getCoordinates(outloc)->invSg(); } Field3D Grad_par(const Field3D& var, CELL_LOC outloc, const std::string& method) { - return var.getCoordinates(outloc)->Grad_par(var, outloc, method); -} - -Field3D Grad_par(const Field3D& var, const std::string& method, CELL_LOC outloc) { - return var.getCoordinates(outloc)->Grad_par(var, outloc, method); + return DDY(var, outloc, method) * var.getCoordinates(outloc)->invSg(); } /******************************************************************************* @@ -86,13 +77,13 @@ Field3D Grad_parP(const Field3D& apar, const Field3D& f) { ASSERT1_FIELDS_COMPATIBLE(apar, f); ASSERT1(f.hasParallelSlices()); - Mesh* mesh = apar.getMesh(); + const Mesh* mesh = apar.getMesh(); Field3D result{emptyFrom(f)}; - int ncz = mesh->LocalNz; + const int ncz = mesh->LocalNz; - Coordinates* metric = apar.getCoordinates(); + const Coordinates* metric = apar.getCoordinates(); Field3D gys{emptyFrom(f)}; @@ -101,8 +92,8 @@ Field3D Grad_parP(const Field3D& apar, const Field3D& f) { for (int y = 1; y <= mesh->LocalNy - 2; y++) { for (int z = 0; z < ncz; z++) { gys(x, y, z) = (f.yup()(x, y + 1, z) - f.ydown()(x, y - 1, z)) - / (0.5 * metric->dy(x, y + 1, z) + metric->dy(x, y, z) - + 0.5 * metric->dy(x, y - 1, z)); + / ((0.5 * metric->dy(x, y + 1, z)) + metric->dy(x, y, z) + + (0.5 * metric->dy(x, y - 1, z))); } } } @@ -110,19 +101,19 @@ Field3D Grad_parP(const Field3D& apar, const Field3D& f) { for (int x = 1; x <= mesh->LocalNx - 2; x++) { for (int y = mesh->ystart; y <= mesh->yend; y++) { for (int z = 0; z < ncz; z++) { - BoutReal by = 1. / sqrt(metric->g_22(x, y, z)); + const 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 @@ -198,46 +189,34 @@ Field3D Grad_parP(const Field3D& apar, const Field3D& f) { * vparallel times the parallel derivative along unperturbed B-field *******************************************************************************/ -Coordinates::FieldMetric Vpar_Grad_par(const Field2D& v, const Field2D& f, - CELL_LOC outloc, const std::string& method) { - return f.getCoordinates(outloc)->Vpar_Grad_par(v, f, outloc, method); -} - -Coordinates::FieldMetric Vpar_Grad_par(const Field2D& v, const Field2D& f, - const std::string& method, CELL_LOC outloc) { - return f.getCoordinates(outloc)->Vpar_Grad_par(v, f, outloc, method); +bout::FieldMetric Vpar_Grad_par(const Field2D& v, const Field2D& f, CELL_LOC outloc, + const std::string& method) { + return VDDY(v, f, outloc, method) * f.getCoordinates(outloc)->invSg(); } Field3D Vpar_Grad_par(const Field3D& v, const Field3D& f, CELL_LOC outloc, const std::string& method) { - return f.getCoordinates(outloc)->Vpar_Grad_par(v, f, outloc, method); -} - -Field3D Vpar_Grad_par(const Field3D& v, const Field3D& f, const std::string& method, - CELL_LOC outloc) { - return f.getCoordinates(outloc)->Vpar_Grad_par(v, f, outloc, method); + return VDDY(v, f, outloc, method) * f.getCoordinates(outloc)->invSg(); } /******************************************************************************* * Div_par * parallel divergence operator B \partial_{||} (F/B) *******************************************************************************/ -Coordinates::FieldMetric Div_par(const Field2D& f, CELL_LOC outloc, - const std::string& method) { - return f.getCoordinates(outloc)->Div_par(f, outloc, method); -} +bout::FieldMetric Div_par(const Field2D& f, CELL_LOC outloc, const std::string& method) { + const auto& Bxy_outloc = f.getCoordinates(outloc)->Bxy(); + // Need Bxy at location of f, which might be different from outloc + const auto& Bxy_floc = f.getCoordinates()->Bxy(); -Coordinates::FieldMetric Div_par(const Field2D& f, const std::string& method, - CELL_LOC outloc) { - return f.getCoordinates(outloc)->Div_par(f, outloc, method); + return Bxy_outloc * Grad_par(bout::FieldMetric{f / Bxy_floc}, outloc, method); } Field3D Div_par(const Field3D& f, CELL_LOC outloc, const std::string& method) { - return f.getCoordinates(outloc)->Div_par(f, outloc, method); -} + const auto& Bxy_outloc = f.getCoordinates(outloc)->Bxy(); + // Need Bxy at location of f, which might be different from outloc + const auto& Bxy_floc = f.getCoordinates()->Bxy(); -Field3D Div_par(const Field3D& f, const std::string& method, CELL_LOC outloc) { - return f.getCoordinates(outloc)->Div_par(f, outloc, method); + return Bxy_outloc * Grad_par(Field3DParallel{f} / Bxy_floc, outloc, method); } Field3D Div_par(const Field3D& f, const Field3D& v) { @@ -247,29 +226,29 @@ Field3D Div_par(const Field3D& f, const Field3D& v) { // Parallel divergence, using velocities at cell boundaries // Note: Not guaranteed to be flux conservative - Mesh* mesh = f.getMesh(); + const Mesh* mesh = f.getMesh(); Field3D result{emptyFrom(f)}; - Coordinates* coord = f.getCoordinates(); + const Coordinates* coord = f.getCoordinates(); for (int i = mesh->xstart; i <= mesh->xend; i++) { 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))); @@ -286,13 +265,13 @@ Field3D Div_par(const Field3D& f, const Field3D& v) { Field3D Div_par_flux(const Field3D& v, const Field3D& f, CELL_LOC outloc, const std::string& method) { - Coordinates* metric = f.getCoordinates(outloc); + const Coordinates* metric = f.getCoordinates(outloc); - auto Bxy_floc = f.getCoordinates()->Bxy; + auto Bxy_floc = f.getCoordinates()->Bxy(); if (!f.hasParallelSlices()) { - Field3D f_B = f / Bxy_floc; - return metric->Bxy * FDDY(v, f_B, outloc, method) / sqrt(metric->g_22); + const Field3D f_B = f / Bxy_floc; + return metric->Bxy() * FDDY(v, f_B, outloc, method) / sqrt(metric->g_22()); } // Need to modify yup and ydown fields @@ -301,12 +280,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); -} - -Field3D Div_par_flux(const Field3D& v, const Field3D& f, const std::string& method, - CELL_LOC outloc) { - return Div_par_flux(v, f, outloc, method); + return metric->Bxy() * FDDY(v, f_B, outloc, method) / sqrt(metric->g_22()); } /******************************************************************************* @@ -318,13 +292,23 @@ Field3D Div_par_flux(const Field3D& v, const Field3D& f, const std::string& meth * Note: For parallel Laplacian use LaplacePar *******************************************************************************/ -Coordinates::FieldMetric Grad2_par2(const Field2D& f, CELL_LOC outloc, - const std::string& method) { - return f.getCoordinates(outloc)->Grad2_par2(f, outloc, method); +bout::FieldMetric Grad2_par2(const Field2D& f, CELL_LOC outloc, + const std::string& method) { + const auto& coords = *f.getCoordinates(outloc); + + return coords.Grad2_par2_DDY_invSg(outloc, method) * DDY(f, outloc, method) + + D2DY2(f, outloc, method) / coords.g_22(); } Field3D Grad2_par2(const Field3D& f, CELL_LOC outloc, const std::string& method) { - return f.getCoordinates(outloc)->Grad2_par2(f, outloc, method); + if (outloc == CELL_DEFAULT) { + outloc = f.getLocation(); + } + + const auto& coords = *f.getCoordinates(outloc); + + return coords.Grad2_par2_DDY_invSg(outloc, method) * DDY(f, outloc, method) + + D2DY2(f, outloc, method) / coords.g_22(); } /******************************************************************************* @@ -332,8 +316,7 @@ Field3D Grad2_par2(const Field3D& f, CELL_LOC outloc, const std::string& method) * Parallel divergence of diffusive flux, K*Grad_par *******************************************************************************/ -Coordinates::FieldMetric Div_par_K_Grad_par(BoutReal kY, const Field2D& f, - CELL_LOC outloc) { +bout::FieldMetric Div_par_K_Grad_par(BoutReal kY, const Field2D& f, CELL_LOC outloc) { return kY * Grad2_par2(f, outloc); } @@ -341,8 +324,8 @@ Field3D Div_par_K_Grad_par(BoutReal kY, const Field3D& f, CELL_LOC outloc) { return kY * Grad2_par2(f, outloc); } -Coordinates::FieldMetric Div_par_K_Grad_par(const Field2D& kY, const Field2D& f, - CELL_LOC outloc) { +bout::FieldMetric Div_par_K_Grad_par(const Field2D& kY, const Field2D& f, + CELL_LOC outloc) { if (outloc == CELL_DEFAULT) { outloc = f.getLocation(); } @@ -405,24 +388,24 @@ Field3D Div_par_K_Grad_par_mod(const Field3D& Kin, const Field3D& fin, Field3D& // Upper cell edge const BoutReal c_up = 0.5 * (Kin[i] + K_up[iyp]); // K at the upper boundary const BoutReal J_up = - 0.5 * (coord->J[i] + coord->J.yup()[iyp]); // Jacobian at boundary - const BoutReal g_22_up = 0.5 * (coord->g_22[i] + coord->g_22.yup()[iyp]); + 0.5 * (coord->J()[i] + coord->J().yup()[iyp]); // Jacobian at boundary + const BoutReal g_22_up = 0.5 * (coord->g_22()[i] + coord->g_22().yup()[iyp]); const BoutReal gradient_up = - 2. * (f_up[iyp] - fin[i]) / (coord->dy[i] + coord->dy.yup()[iyp]); + 2. * (f_up[iyp] - fin[i]) / (coord->dy()[i] + coord->dy().yup()[iyp]); const BoutReal flux_up = c_up * J_up * gradient_up / g_22_up; // Lower cell edge const BoutReal c_down = 0.5 * (Kin[i] + K_down[iym]); // K at the lower boundary const BoutReal J_down = - 0.5 * (coord->J[i] + coord->J.ydown()[iym]); // Jacobian at boundary - const BoutReal g_22_down = 0.5 * (coord->g_22[i] + coord->g_22.ydown()[iym]); + 0.5 * (coord->J()[i] + coord->J().ydown()[iym]); // Jacobian at boundary + const BoutReal g_22_down = 0.5 * (coord->g_22()[i] + coord->g_22().ydown()[iym]); const BoutReal gradient_down = - 2. * (fin[i] - f_down[iym]) / (coord->dy[i] + coord->dy.ydown()[iym]); + 2. * (fin[i] - f_down[iym]) / (coord->dy()[i] + coord->dy().ydown()[iym]); const BoutReal flux_down = c_down * J_down * gradient_down / g_22_down; - result[i] = (flux_up - flux_down) / (coord->dy[i] * coord->J[i]); + result[i] = (flux_up - flux_down) / (coord->dy()[i] * coord->J()[i]); } return result; @@ -445,27 +428,29 @@ Field3D Div_par_K_Grad_par_mod(const Field3D& Kin, const Field3D& fin, Field3D& const bool is_periodic_y = mesh->periodicY(ix); if (bndry_flux || is_periodic_y || !mesh->lastY(ix) || (iy != mesh->yend)) { - const BoutReal c = 0.5 * (K[i] + K[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]); - const BoutReal gradient = 2. * (f[iyp] - f[i]) / (coord->dy[i] + coord->dy[iyp]); + const BoutReal c = 0.5 * (K[i] + K[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]); + const BoutReal gradient = + 2. * (f[iyp] - f[i]) / (coord->dy()[i] + coord->dy()[iyp]); 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 || is_periodic_y || !mesh->firstY(ix) || (iy != mesh->ystart)) { - const BoutReal c = 0.5 * (K[i] + K[iym]); // K at the lower boundary - const BoutReal J = 0.5 * (coord->J[i] + coord->J[iym]); // Jacobian at boundary - const BoutReal g_22 = 0.5 * (coord->g_22[i] + coord->g_22[iym]); - const BoutReal gradient = 2. * (f[i] - f[iym]) / (coord->dy[i] + coord->dy[iym]); + const BoutReal c = 0.5 * (K[i] + K[iym]); // K at the lower boundary + const BoutReal J = 0.5 * (coord->J()[i] + coord->J()[iym]); // Jacobian at boundary + const BoutReal g_22 = 0.5 * (coord->g_22()[i] + coord->g_22()[iym]); + const BoutReal gradient = + 2. * (f[i] - f[iym]) / (coord->dy()[i] + coord->dy()[iym]); const BoutReal flux = c * J * gradient / g_22; - result[i] -= flux / (coord->dy[i] * coord->J[i]); - flow_ylow[i] = -flux * coord->dx[i] * coord->dz[i]; + result[i] -= flux / (coord->dy()[i] * coord->J()[i]); + flow_ylow[i] = -flux * coord->dx()[i] * coord->dz()[i]; } } @@ -481,16 +466,140 @@ Field3D Div_par_K_Grad_par_mod(const Field3D& Kin, const Field3D& fin, Field3D& * perpendicular Laplacian operator *******************************************************************************/ -Coordinates::FieldMetric Delp2(const Field2D& f, CELL_LOC outloc, bool useFFT) { - return f.getCoordinates(outloc)->Delp2(f, outloc, useFFT); +bout::FieldMetric Delp2(const Field2D& f, CELL_LOC outloc, [[maybe_unused]] bool useFFT) { + const auto& coords = *f.getCoordinates(outloc); + return coords.G1() * DDX(f, outloc) + coords.g11() * D2DX2(f, outloc); } Field3D Delp2(const Field3D& f, CELL_LOC outloc, bool useFFT) { - return f.getCoordinates(outloc)->Delp2(f, outloc, useFFT); + if (outloc == CELL_DEFAULT) { + outloc = f.getLocation(); + } + + ASSERT1(f.getLocation() == outloc); + const auto* mesh = f.getMesh(); + + if (mesh->GlobalNx == 1 && mesh->GlobalNz == 1) { + // copy mesh, location, etc + return f * 0; + } + ASSERT2(mesh->xstart > 0); // Need at least one guard cell; + + Field3D result{emptyFrom(f).setLocation(outloc)}; + + if (useFFT and not bout::build::use_metric_3d and mesh->getNZPE() == 1) { + const int ncz = mesh->LocalNz; + + // Allocate memory + auto ft = Matrix(mesh->LocalNx, (ncz / 2) + 1); + auto delft = Matrix(mesh->LocalNx, (ncz / 2) + 1); + + // Loop over y indices + // Note: should not include y-guard or y-boundary points here as that would + // use values from corner cells in dx, which may not be initialised. + for (int jy = mesh->ystart; jy <= mesh->yend; jy++) { + + // Take forward FFT + + for (int jx = 0; jx < mesh->LocalNx; jx++) { + rfft(&f(jx, jy, 0), ncz, &ft(jx, 0)); + } + + // Loop over kz + for (int jz = 0; jz <= ncz / 2; jz++) { + + // No smoothing in the x direction + for (int jx = mesh->xstart; jx <= mesh->xend; jx++) { + // Perform x derivative + + dcomplex a; + dcomplex b; + dcomplex c; + laplace_tridag_coefs(jx, jy, jz, a, b, c, nullptr, nullptr, outloc); + + delft(jx, jz) = a * ft(jx - 1, jz) + b * ft(jx, jz) + c * ft(jx + 1, jz); + } + } + + // Reverse FFT + for (int jx = mesh->xstart; jx <= mesh->xend; jx++) { + + irfft(&delft(jx, 0), ncz, &result(jx, jy, 0)); + } + } + } else { + const auto& coords = *f.getCoordinates(outloc); + result = coords.G1() * DDX(f, outloc) + coords.G3() * DDZ(f, outloc) + + coords.g11() * D2DX2(f, outloc) + coords.g33() * D2DZ2(f, outloc) + + 2 * coords.g13() * D2DXDZ(f, outloc); + } + + ASSERT2(result.getLocation() == outloc); + + return result; } FieldPerp Delp2(const FieldPerp& f, CELL_LOC outloc, bool useFFT) { - return f.getCoordinates(outloc)->Delp2(f, outloc, useFFT); + if (outloc == CELL_DEFAULT) { + outloc = f.getLocation(); + } + + ASSERT1(f.getLocation() == outloc); + const auto* mesh = f.getMesh(); + + if (mesh->GlobalNx == 1 && mesh->GlobalNz == 1) { + // copy mesh, location, etc + return f * 0; + } + ASSERT2(mesh->xstart > 0); // Need at least one guard cell + + FieldPerp result{emptyFrom(f).setLocation(outloc)}; + + const int jy = f.getIndex(); + result.setIndex(jy); + + if (useFFT and mesh->getNZPE() == 1) { + const int ncz = mesh->LocalNz; + + // Allocate memory + auto ft = Matrix(mesh->LocalNx, (ncz / 2) + 1); + auto delft = Matrix(mesh->LocalNx, (ncz / 2) + 1); + + // Take forward FFT + for (int jx = 0; jx < mesh->LocalNx; jx++) { + rfft(&f(jx, 0), ncz, &ft(jx, 0)); + } + + // Loop over kz + for (int jz = 0; jz <= ncz / 2; jz++) { + + // No smoothing in the x direction + for (int jx = mesh->xstart; jx <= mesh->xend; jx++) { + // Perform x derivative + + dcomplex a; + dcomplex b; + dcomplex c; + laplace_tridag_coefs(jx, jy, jz, a, b, c); + + delft(jx, jz) = a * ft(jx - 1, jz) + b * ft(jx, jz) + c * ft(jx + 1, jz); + } + } + + // Reverse FFT + for (int jx = mesh->xstart; jx <= mesh->xend; jx++) { + irfft(&delft(jx, 0), ncz, &result(jx, 0)); + } + + } else { + throw BoutException("Non-fourier Delp2 not currently implented for FieldPerp."); + // Would be the following but don't have standard derivative operators for FieldPerps + // yet + // result = G1 * ::DDX(f, outloc) + G3 * ::DDZ(f, outloc) + g11 * ::D2DX2(f, outloc) + // + g33 * ::D2DZ2(f, outloc) + 2 * g13 * ::D2DXDZ(f, outloc); + }; + + return result; } /******************************************************************************* @@ -500,9 +609,9 @@ FieldPerp Delp2(const FieldPerp& f, CELL_LOC outloc, bool useFFT) { * Laplace_perp = Laplace - Laplace_par *******************************************************************************/ -Coordinates::FieldMetric Laplace_perp(const Field2D& f, CELL_LOC outloc, - const std::string& dfdy_boundary_condition, - const std::string& dfdy_region) { +bout::FieldMetric Laplace_perp(const Field2D& f, CELL_LOC outloc, + const std::string& dfdy_boundary_condition, + const std::string& dfdy_region) { return Laplace(f, outloc, dfdy_boundary_condition, dfdy_region) - Laplace_par(f, outloc); } @@ -522,12 +631,18 @@ Field3D Laplace_perp(const Field3D& f, CELL_LOC outloc, * *******************************************************************************/ -Coordinates::FieldMetric Laplace_par(const Field2D& f, CELL_LOC outloc) { - return f.getCoordinates(outloc)->Laplace_par(f, outloc); +bout::FieldMetric Laplace_par(const Field2D& f, CELL_LOC outloc) { + const auto& coords = *f.getCoordinates(outloc); + return D2DY2(f, outloc) / coords.g_22() + + DDY(bout::FieldMetric{coords.J() / coords.g_22()}, outloc) * DDY(f, outloc) + / coords.J(); } Field3D Laplace_par(const Field3D& f, CELL_LOC outloc) { - return f.getCoordinates(outloc)->Laplace_par(f, outloc); + const auto& coords = *f.getCoordinates(outloc); + return D2DY2(f, outloc) / coords.g_22() + + DDY(coords.J().asField3DParallel() / coords.g_22(), outloc) * DDY(f, outloc) + / coords.J(); } /******************************************************************************* @@ -535,18 +650,31 @@ Field3D Laplace_par(const Field3D& f, CELL_LOC outloc) { * Full Laplacian operator on scalar field *******************************************************************************/ -Coordinates::FieldMetric Laplace(const Field2D& f, CELL_LOC outloc, - const std::string& dfdy_boundary_condition, - const std::string& dfdy_region) { - return f.getCoordinates(outloc)->Laplace(f, outloc, dfdy_boundary_condition, - dfdy_region); +bout::FieldMetric Laplace(const Field2D& f, CELL_LOC outloc, + const std::string& dfdy_boundary_condition, + const std::string& dfdy_region) { + const auto& coords = *f.getCoordinates(outloc); + + return coords.G1() * DDX(f, outloc) + coords.G2() * DDY(f, outloc) + + coords.g11() * D2DX2(f, outloc) + coords.g22() * D2DY2(f, outloc) + + 2.0 * coords.g12() + * D2DXDY(f, outloc, "DEFAULT", "RGN_NOBNDRY", dfdy_boundary_condition, + dfdy_region); } Field3D Laplace(const Field3D& f, CELL_LOC outloc, const std::string& dfdy_boundary_condition, const std::string& dfdy_region) { - return f.getCoordinates(outloc)->Laplace(f, outloc, dfdy_boundary_condition, - dfdy_region); + const auto& coords = *f.getCoordinates(outloc); + + return coords.G1() * DDX(f, outloc) + coords.G2() * DDY(f, outloc) + + coords.G3() * DDZ(f, outloc) + coords.g11() * D2DX2(f, outloc) + + coords.g22() * D2DY2(f, outloc) + coords.g33() * D2DZ2(f, outloc) + + 2.0 + * (coords.g12() + * D2DXDY(f, outloc, "DEFAULT", "RGN_NOBNDRY", + dfdy_boundary_condition, dfdy_region) + + coords.g13() * D2DXDZ(f, outloc) + coords.g23() * D2DYDZ(f, outloc)); } /******************************************************************************* @@ -555,7 +683,65 @@ Field3D Laplace(const Field3D& f, CELL_LOC outloc, *******************************************************************************/ Field2D Laplace_perpXY(const Field2D& A, const Field2D& f) { - return f.getCoordinates()->Laplace_perpXY(A, f); +#if BOUT_USE_METRIC_3D + throw BoutException("Coordinates::Laplace_perpXY for 3D metric not implemented"); +#else + const auto& coords = *f.getCoordinates(); + + Field2D result; + result.allocate(); + for (auto i : result.getRegion(RGN_NOBNDRY)) { + result[i] = 0.; + + // 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(coords.J()); + const BoutReal outer_x_g11 = outer_x_avg(coords.g11()); + const BoutReal outer_x_dx = outer_x_avg(coords.dx()); + const BoutReal outer_x_value = outer_x_A * outer_x_J * outer_x_g11 + / (coords.J()[i] * outer_x_dx * coords.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(coords.J()); + const BoutReal inner_x_g11 = inner_x_avg(coords.g11()); + const BoutReal inner_x_dx = inner_x_avg(coords.dx()); + const BoutReal inner_x_value = inner_x_A * inner_x_J * inner_x_g11 + / (coords.J()[i] * inner_x_dx * coords.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(coords.J()); + const BoutReal upper_y_g_22 = upper_y_avg(coords.g_22()); + const BoutReal upper_y_g23 = upper_y_avg(coords.g23()); + const BoutReal upper_y_g_23 = upper_y_avg(coords.g_23()); + const BoutReal upper_y_dy = upper_y_avg(coords.dy()); + const BoutReal upper_y_value = + -upper_y_A * upper_y_J * upper_y_g23 * upper_y_g_23 + / (upper_y_g_22 * coords.J()[i] * upper_y_dy * coords.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(coords.J()); + const BoutReal lower_y_g_22 = lower_y_avg(coords.g_22()); + const BoutReal lower_y_g23 = lower_y_avg(coords.g23()); + const BoutReal lower_y_g_23 = lower_y_avg(coords.g_23()); + const BoutReal lower_y_dy = lower_y_avg(coords.dy()); + const BoutReal lower_y_value = + -lower_y_A * lower_y_J * lower_y_g23 * lower_y_g_23 + / (lower_y_g_22 * coords.J()[i] * lower_y_dy * coords.dy()[i]); + result[i] += lower_y_value * (f[i.ym()] - f[i]); + } + + return result; +#endif } /******************************************************************************* @@ -564,8 +750,8 @@ Field2D Laplace_perpXY(const Field2D& A, const Field2D& f) { * Used for ExB terms and perturbed B field using A_|| *******************************************************************************/ -Coordinates::FieldMetric b0xGrad_dot_Grad(const Field2D& phi, const Field2D& A, - CELL_LOC outloc) { +bout::FieldMetric b0xGrad_dot_Grad(const Field2D& phi, const Field2D& A, + CELL_LOC outloc) { if (outloc == CELL_DEFAULT) { outloc = A.getLocation(); @@ -573,19 +759,19 @@ Coordinates::FieldMetric b0xGrad_dot_Grad(const Field2D& phi, const Field2D& A, ASSERT1(phi.getMesh() == A.getMesh()); - Coordinates* metric = phi.getCoordinates(outloc); + const Coordinates* metric = phi.getCoordinates(outloc); // Calculate phi derivatives - Coordinates::FieldMetric dpdx = DDX(phi, outloc); - Coordinates::FieldMetric dpdy = DDY(phi, outloc); + const bout::FieldMetric dpdx = DDX(phi, outloc); + const bout::FieldMetric dpdy = DDY(phi, outloc); // Calculate advection velocity - Coordinates::FieldMetric vx = -metric->g_23 * dpdy; - Coordinates::FieldMetric vy = metric->g_23 * dpdx; + const bout::FieldMetric vx = -metric->g_23() * dpdy; + const bout::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); + bout::FieldMetric result = VDDX(vx, A, outloc) + VDDY(vy, A, outloc); + result /= metric->J() * sqrt(metric->g_22()); ASSERT1(result.getLocation() == outloc); @@ -603,29 +789,29 @@ Field3D b0xGrad_dot_Grad(const Field2D& phi, const Field3D& A, CELL_LOC outloc) ASSERT1(phi.getMesh() == A.getMesh()); - Mesh* mesh = phi.getMesh(); + const Mesh* mesh = phi.getMesh(); - Coordinates* metric = phi.getCoordinates(outloc); + const Coordinates* metric = phi.getCoordinates(outloc); // Calculate phi derivatives - Coordinates::FieldMetric dpdx = DDX(phi, outloc); - Coordinates::FieldMetric dpdy = DDY(phi, outloc); + const bout::FieldMetric dpdx = DDX(phi, outloc); + const bout::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 bout::FieldMetric vx = -metric->g_23() * dpdy; + const bout::FieldMetric vy = metric->g_23() * dpdx; + bout::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 + ")"; @@ -644,22 +830,22 @@ Field3D b0xGrad_dot_Grad(const Field3D& p, const Field2D& A, CELL_LOC outloc) { ASSERT1(p.getMesh() == A.getMesh()); - Coordinates* metric = p.getCoordinates(outloc); + const 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 + ")"; @@ -678,28 +864,28 @@ Field3D b0xGrad_dot_Grad(const Field3D& phi, const Field3D& A, CELL_LOC outloc) ASSERT1(phi.getMesh() == A.getMesh()); - Mesh* mesh = phi.getMesh(); + const Mesh* mesh = phi.getMesh(); - Coordinates* metric = phi.getCoordinates(outloc); + const 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 + ")"; @@ -715,9 +901,8 @@ Field3D b0xGrad_dot_Grad(const Field3D& phi, const Field3D& A, CELL_LOC outloc) * Terms of form b0 x Grad(f) dot Grad(g) / B = [f, g] *******************************************************************************/ -Coordinates::FieldMetric bracket(const Field2D& f, const Field2D& g, - BRACKET_METHOD method, CELL_LOC outloc, - Solver* UNUSED(solver)) { +bout::FieldMetric bracket(const Field2D& f, const Field2D& g, BRACKET_METHOD method, + CELL_LOC outloc, Solver* UNUSED(solver)) { ASSERT1_FIELDS_COMPATIBLE(f, g); if (outloc == CELL_DEFAULT) { @@ -725,7 +910,7 @@ Coordinates::FieldMetric bracket(const Field2D& f, const Field2D& g, } ASSERT1(outloc == g.getLocation()); - Coordinates::FieldMetric result{emptyFrom(f)}; + bout::FieldMetric result{emptyFrom(f)}; if ((method == BRACKET_SIMPLE) || (method == BRACKET_ARAKAWA)) { // Use a subset of terms for comparison to BOUT-06 @@ -733,7 +918,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; } @@ -747,18 +932,18 @@ Field3D bracket(const Field3D& f, const Field2D& g, BRACKET_METHOD method, } ASSERT1(outloc == g.getLocation()); - [[maybe_unused]] Mesh* mesh = f.getMesh(); + [[maybe_unused]] const Mesh* mesh = f.getMesh(); Field3D result{emptyFrom(f).setLocation(outloc)}; - Coordinates* metric = f.getCoordinates(outloc); + const Coordinates* metric = f.getCoordinates(outloc); switch (method) { case BRACKET_CTU: { // First order Corner Transport Upwind method // P.Collela JCP 87, 171-200 (1990) - if (!solver) { + if (solver == nullptr) { throw BoutException("CTU method requires access to the solver"); } @@ -768,13 +953,14 @@ 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; + BoutReal gp; + BoutReal 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)); @@ -808,15 +994,21 @@ 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 int jy = j2D.y(), jx = j2D.x(); - const int xm = jx - 1, xp = jx + 1; + const BoutReal spacingFactor = 1.0 / (12 * metric->dz()[j2D] * metric->dx()[j2D]); + const int jy = j2D.y(); + const int jx = j2D.x(); + const int xm = jx - 1; + const int xp = jx + 1; // Extract relevant Field2D values - const BoutReal gxm = g(xm, jy), gc = g(jx, jy), gxp = g(xp, jy); + const BoutReal gxm = g(xm, jy); + const BoutReal gc = g(jx, jy); + const BoutReal gxp = g(xp, jy); // Index Field3D as 2D to get start of z data block - const auto fxm = f(xm, jy), fc = f(jx, jy), fxp = f(xp, jy); + const auto fxm = f(xm, jy); + const auto fc = f(jx, jy); + const auto fxp = f(xp, jy); // Here we split the loop over z into three parts; the first value, the middle block // and the last value @@ -831,8 +1023,8 @@ Field3D bracket(const Field3D& f, const Field2D& g, BRACKET_METHOD method, const BoutReal Jpp = 2 * (fc[jzp] - fc[jzm]) * (gxp - gxm); // J+x - const BoutReal Jpx = gxp * (fxp[jzp] - fxp[jzm]) - gxm * (fxm[jzp] - fxm[jzm]) - + gc * (fxp[jzm] - fxp[jzp] - fxm[jzm] + fxm[jzp]); + const BoutReal Jpx = (gxp * (fxp[jzp] - fxp[jzm])) - (gxm * (fxm[jzp] - fxm[jzm])) + + (gc * (fxp[jzm] - fxp[jzp] - fxm[jzm] + fxm[jzp])); result(jx, jy, 0) = (Jpp + Jpx) * spacingFactor; } @@ -846,8 +1038,8 @@ Field3D bracket(const Field3D& f, const Field2D& g, BRACKET_METHOD method, const BoutReal Jpp = 2 * (fc[jzp] - fc[jzm]) * (gxp - gxm); // J+x - const BoutReal Jpx = gxp * (fxp[jzp] - fxp[jzm]) - gxm * (fxm[jzp] - fxm[jzm]) - + gc * (fxp[jzm] - fxp[jzp] - fxm[jzm] + fxm[jzp]); + const BoutReal Jpx = (gxp * (fxp[jzp] - fxp[jzm])) - (gxm * (fxm[jzp] - fxm[jzm])) + + (gc * (fxp[jzm] - fxp[jzp] - fxm[jzm] + fxm[jzp])); result(jx, jy, jz) = (Jpp + Jpx) * spacingFactor; } @@ -861,8 +1053,8 @@ Field3D bracket(const Field3D& f, const Field2D& g, BRACKET_METHOD method, const BoutReal Jpp = 2 * (fc[jzp] - fc[jzm]) * (gxp - gxm); // J+x - const BoutReal Jpx = gxp * (fxp[jzp] - fxp[jzm]) - gxm * (fxm[jzp] - fxm[jzm]) - + gc * (fxp[jzm] - fxp[jzp] - fxm[jzm] + fxm[jzp]); + const BoutReal Jpx = (gxp * (fxp[jzp] - fxp[jzm])) - (gxm * (fxm[jzp] - fxm[jzm])) + + (gc * (fxp[jzm] - fxp[jzp] - fxm[jzm] + fxm[jzp])); result(jx, jy, ncz - 1) = (Jpp + Jpx) * spacingFactor; } @@ -880,7 +1072,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; @@ -914,8 +1106,8 @@ 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; + const Coordinates* metric = f.getCoordinates(outloc); + result = b0xGrad_dot_Grad(f, g, outloc) / metric->Bxy(); } } @@ -934,7 +1126,7 @@ Field3D bracket(const Field3D& f, const Field3D& g, BRACKET_METHOD method, Field3D result{emptyFrom(f).setLocation(outloc)}; - Coordinates* metric = f.getCoordinates(outloc); + const Coordinates* metric = f.getCoordinates(outloc); if (mesh->GlobalNx == 1 || mesh->GlobalNz == 1) { result = 0; @@ -947,32 +1139,33 @@ Field3D bracket(const Field3D& f, const Field3D& g, BRACKET_METHOD method, // First order Corner Transport Upwind method // P.Collela JCP 87, 171-200 (1990) #if not(BOUT_USE_METRIC_3D) - if (!solver) { + if (solver == nullptr) { throw BoutException("CTU method requires access to the solver"); } // Get current timestep - BoutReal dt = solver->getCurrentTimestep(); + const BoutReal dt = solver->getCurrentTimestep(); - FieldPerp vx(mesh), vz(mesh); + FieldPerp vx(mesh); + FieldPerp vz(mesh); vx.allocate(); vx.setLocation(outloc); 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++) { - int zm = (z - 1 + ncz) % ncz; - int zp = (z + 1) % ncz; + const int zm = (z - 1 + ncz) % ncz; + const int zp = (z + 1) % ncz; // Vx = DDZ(f) vx(x, z) = (f(x, y, zp) - f(x, y, zm)) / (2. * metric->dz(x, y, z)); // Vz = -DDX(f) vz(x, z) = (f(x - 1, y, z) - f(x + 1, y, z)) - / (0.5 * metric->dx(x - 1, y) + metric->dx(x, y) - + 0.5 * metric->dx(x + 1, y)); + / ((0.5 * metric->dx(x - 1, y)) + metric->dx(x, y) + + (0.5 * metric->dx(x + 1, y))); // Set stability condition solver->setMaxTimestep(fabs(metric->dx(x, y)) / (fabs(vx(x, z)) + 1e-16)); @@ -984,33 +1177,34 @@ 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; + BoutReal gp; + BoutReal gm; // X differencing if (vx(x, z) > 0.0) { gp = g(x, y, z) - + (0.5 * dt / metric->dz(x, y)) - * ((vz(x, z) > 0) ? vz(x, z) * (g(x, y, zm) - g(x, y, z)) - : vz(x, z) * (g(x, y, z) - g(x, y, zp))); + + ((0.5 * dt / metric->dz(x, y)) + * ((vz(x, z) > 0) ? vz(x, z) * (g(x, y, zm) - g(x, y, z)) + : vz(x, z) * (g(x, y, z) - g(x, y, zp)))); gm = g(x - 1, y, z) - + (0.5 * dt / metric->dz(x, y)) - * ((vz(x, z) > 0) ? vz(x, z) * (g(x - 1, y, zm) - g(x - 1, y, z)) - : vz(x, z) * (g(x - 1, y, z) - g(x - 1, y, zp))); + + ((0.5 * dt / metric->dz(x, y)) + * ((vz(x, z) > 0) ? vz(x, z) * (g(x - 1, y, zm) - g(x - 1, y, z)) + : vz(x, z) * (g(x - 1, y, z) - g(x - 1, y, zp)))); } else { gp = g(x + 1, y, z) - + (0.5 * dt / metric->dz(x, y)) - * ((vz(x, z) > 0) ? vz(x, z) * (g(x + 1, y, zm) - g(x + 1, y, z)) - : vz[x][z] * (g(x + 1, y, z) - g(x + 1, y, zp))); + + ((0.5 * dt / metric->dz(x, y)) + * ((vz(x, z) > 0) ? vz(x, z) * (g(x + 1, y, zm) - g(x + 1, y, z)) + : vz[x][z] * (g(x + 1, y, z) - g(x + 1, y, zp)))); gm = g(x, y, z) - + (0.5 * dt / metric->dz(x, y)) - * ((vz(x, z) > 0) ? vz(x, z) * (g(x, y, zm) - g(x, y, z)) - : vz(x, z) * (g(x, y, z) - g(x, y, zp))); + + ((0.5 * dt / metric->dz(x, y)) + * ((vz(x, z) > 0) ? vz(x, z) * (g(x, y, zm) - g(x, y, z)) + : vz(x, z) * (g(x, y, z) - g(x, y, zp)))); } result(x, y, z) = vx(x, z) * (gp - gm) / metric->dx(x, y); @@ -1018,24 +1212,24 @@ Field3D bracket(const Field3D& f, const Field3D& g, BRACKET_METHOD method, // Z differencing if (vz(x, z) > 0.0) { gp = g(x, y, z) - + (0.5 * dt / metric->dx(x, y)) - * ((vx[x][z] > 0) ? vx[x][z] * (g(x - 1, y, z) - g(x, y, z)) - : vx[x][z] * (g(x, y, z) - g(x + 1, y, z))); + + ((0.5 * dt / metric->dx(x, y)) + * ((vx[x][z] > 0) ? vx[x][z] * (g(x - 1, y, z) - g(x, y, z)) + : vx[x][z] * (g(x, y, z) - g(x + 1, y, z)))); gm = g(x, y, zm) - + (0.5 * dt / metric->dx(x, y)) - * ((vx(x, z) > 0) ? vx(x, z) * (g(x - 1, y, zm) - g(x, y, zm)) - : vx(x, z) * (g(x, y, zm) - g(x + 1, y, zm))); + + ((0.5 * dt / metric->dx(x, y)) + * ((vx(x, z) > 0) ? vx(x, z) * (g(x - 1, y, zm) - g(x, y, zm)) + : vx(x, z) * (g(x, y, zm) - g(x + 1, y, zm)))); } else { gp = g(x, y, zp) - + (0.5 * dt / metric->dx(x, y)) - * ((vx(x, z) > 0) ? vx(x, z) * (g(x - 1, y, zp) - g(x, y, zp)) - : vx(x, z) * (g(x, y, zp) - g(x + 1, y, zp))); + + ((0.5 * dt / metric->dx(x, y)) + * ((vx(x, z) > 0) ? vx(x, z) * (g(x - 1, y, zp) - g(x, y, zp)) + : vx(x, z) * (g(x, y, zp) - g(x + 1, y, zp)))); gm = g(x, y, z) - + (0.5 * dt / metric->dx(x, y)) - * ((vx(x, z) > 0) ? vx(x, z) * (g(x - 1, y, z) - g(x, y, z)) - : vx(x, z) * (g(x, y, z) - g(x + 1, y, z))); + + ((0.5 * dt / metric->dx(x, y)) + * ((vx(x, z) > 0) ? vx(x, z) * (g(x - 1, y, z) - g(x, y, z)) + : vx(x, z) * (g(x, y, z) - g(x + 1, y, z)))); } result(x, y, z) += vz(x, z) * (gp - gm) / metric->dz(x, y); @@ -1058,13 +1252,19 @@ 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; - - const auto Fxm = f_temp(xm, jy), Fx = f_temp(jx, jy), Fxp = f_temp(xp, jy); - const auto Gxm = g_temp(xm, jy), Gx = g_temp(jx, jy), Gxp = g_temp(xp, jy); + const int jy = j2D.y(); + const int jx = j2D.x(); + const int xm = jx - 1; + const int xp = jx + 1; + + const auto Fxm = f_temp(xm, jy); + const auto Fx = f_temp(jx, jy); + const auto Fxp = f_temp(xp, jy); + const auto Gxm = g_temp(xm, jy); + const auto Gx = g_temp(jx, jy); + const auto Gxp = g_temp(xp, jy); // Here we split the loop over z into three parts; the first value, the middle block // and the last value @@ -1080,18 +1280,18 @@ Field3D bracket(const Field3D& f, const Field3D& g, BRACKET_METHOD method, #endif // J++ = DDZ(f)*DDX(g) - DDX(f)*DDZ(g) - const BoutReal Jpp = ((Fx[jzp] - Fx[jzm]) * (Gxp[jz] - Gxm[jz]) - - (Fxp[jz] - Fxm[jz]) * (Gx[jzp] - Gx[jzm])); + const BoutReal Jpp = (((Fx[jzp] - Fx[jzm]) * (Gxp[jz] - Gxm[jz])) + - ((Fxp[jz] - Fxm[jz]) * (Gx[jzp] - Gx[jzm]))); // J+x const BoutReal Jpx = - (Gxp[jz] * (Fxp[jzp] - Fxp[jzm]) - Gxm[jz] * (Fxm[jzp] - Fxm[jzm]) - - Gx[jzp] * (Fxp[jzp] - Fxm[jzp]) + Gx[jzm] * (Fxp[jzm] - Fxm[jzm])); + ((Gxp[jz] * (Fxp[jzp] - Fxp[jzm])) - (Gxm[jz] * (Fxm[jzp] - Fxm[jzm])) + - (Gx[jzp] * (Fxp[jzp] - Fxm[jzp])) + (Gx[jzm] * (Fxp[jzm] - Fxm[jzm]))); // Jx+ const BoutReal Jxp = - (Gxp[jzp] * (Fx[jzp] - Fxp[jz]) - Gxm[jzm] * (Fxm[jz] - Fx[jzm]) - - Gxm[jzp] * (Fx[jzp] - Fxm[jz]) + Gxp[jzm] * (Fxp[jz] - Fx[jzm])); + ((Gxp[jzp] * (Fx[jzp] - Fxp[jz])) - (Gxm[jzm] * (Fxm[jz] - Fx[jzm])) + - (Gxm[jzp] * (Fx[jzp] - Fxm[jz])) + (Gxp[jzm] * (Fxp[jz] - Fx[jzm]))); result(jx, jy, jz) = (Jpp + Jpx + Jxp) * spacingFactor; } @@ -1105,18 +1305,18 @@ Field3D bracket(const Field3D& f, const Field3D& g, BRACKET_METHOD method, const int jzm = jz - 1; // J++ = DDZ(f)*DDX(g) - DDX(f)*DDZ(g) - const BoutReal Jpp = ((Fx[jzp] - Fx[jzm]) * (Gxp[jz] - Gxm[jz]) - - (Fxp[jz] - Fxm[jz]) * (Gx[jzp] - Gx[jzm])); + const BoutReal Jpp = (((Fx[jzp] - Fx[jzm]) * (Gxp[jz] - Gxm[jz])) + - ((Fxp[jz] - Fxm[jz]) * (Gx[jzp] - Gx[jzm]))); // J+x const BoutReal Jpx = - (Gxp[jz] * (Fxp[jzp] - Fxp[jzm]) - Gxm[jz] * (Fxm[jzp] - Fxm[jzm]) - - Gx[jzp] * (Fxp[jzp] - Fxm[jzp]) + Gx[jzm] * (Fxp[jzm] - Fxm[jzm])); + ((Gxp[jz] * (Fxp[jzp] - Fxp[jzm])) - (Gxm[jz] * (Fxm[jzp] - Fxm[jzm])) + - (Gx[jzp] * (Fxp[jzp] - Fxm[jzp])) + (Gx[jzm] * (Fxp[jzm] - Fxm[jzm]))); // Jx+ const BoutReal Jxp = - (Gxp[jzp] * (Fx[jzp] - Fxp[jz]) - Gxm[jzm] * (Fxm[jz] - Fx[jzm]) - - Gxm[jzp] * (Fx[jzp] - Fxm[jz]) + Gxp[jzm] * (Fxp[jz] - Fx[jzm])); + ((Gxp[jzp] * (Fx[jzp] - Fxp[jz])) - (Gxm[jzm] * (Fxm[jz] - Fx[jzm])) + - (Gxm[jzp] * (Fx[jzp] - Fxm[jz])) + (Gxp[jzm] * (Fxp[jz] - Fx[jzm]))); result(jx, jy, jz) = (Jpp + Jpx + Jxp) * spacingFactor; } @@ -1131,18 +1331,18 @@ Field3D bracket(const Field3D& f, const Field3D& g, BRACKET_METHOD method, #endif // J++ = DDZ(f)*DDX(g) - DDX(f)*DDZ(g) - const BoutReal Jpp = ((Fx[jzp] - Fx[jzm]) * (Gxp[jz] - Gxm[jz]) - - (Fxp[jz] - Fxm[jz]) * (Gx[jzp] - Gx[jzm])); + const BoutReal Jpp = (((Fx[jzp] - Fx[jzm]) * (Gxp[jz] - Gxm[jz])) + - ((Fxp[jz] - Fxm[jz]) * (Gx[jzp] - Gx[jzm]))); // J+x const BoutReal Jpx = - (Gxp[jz] * (Fxp[jzp] - Fxp[jzm]) - Gxm[jz] * (Fxm[jzp] - Fxm[jzm]) - - Gx[jzp] * (Fxp[jzp] - Fxm[jzp]) + Gx[jzm] * (Fxp[jzm] - Fxm[jzm])); + ((Gxp[jz] * (Fxp[jzp] - Fxp[jzm])) - (Gxm[jz] * (Fxm[jzp] - Fxm[jzm])) + - (Gx[jzp] * (Fxp[jzp] - Fxm[jzp])) + (Gx[jzm] * (Fxp[jzm] - Fxm[jzm]))); // Jx+ const BoutReal Jxp = - (Gxp[jzp] * (Fx[jzp] - Fxp[jz]) - Gxm[jzm] * (Fxm[jz] - Fx[jzm]) - - Gxm[jzp] * (Fx[jzp] - Fxm[jz]) + Gxp[jzm] * (Fxp[jz] - Fx[jzm])); + ((Gxp[jzp] * (Fx[jzp] - Fxp[jz])) - (Gxm[jzm] * (Fxm[jz] - Fx[jzm])) + - (Gxm[jzp] * (Fx[jzp] - Fxm[jz])) + (Gxp[jzm] * (Fxp[jz] - Fx[jzm]))); result(jx, jy, jz) = (Jpp + Jpx + Jxp) * spacingFactor; } @@ -1156,7 +1356,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 660fc51abc..a400028256 100644 --- a/src/mesh/fv_ops.cxx +++ b/src/mesh/fv_ops.cxx @@ -71,9 +71,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!"); } } @@ -89,12 +89,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); @@ -158,7 +158,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) @@ -214,31 +214,32 @@ Field3D Div_par_K_Grad_par(const Field3D& Kin, const Field3D& fin, bool bndry_fl if (bndry_flux || mesh->periodicY(i.x()) || !mesh->lastY(i.x()) || (i.y() != mesh->yend)) { - 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]); + 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]); - const 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]); 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)) { - 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 + 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 - const 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]); const BoutReal gradient = - 2. * (f[i] - fdown[iym]) / (coord->dy[i] + coord->dy[iym]); + 2. * (f[i] - fdown[iym]) / (coord->dy()[i] + coord->dy()[iym]); 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]); } } diff --git a/src/mesh/g_values.cxx b/src/mesh/g_values.cxx new file mode 100644 index 0000000000..cf4713464e --- /dev/null +++ b/src/mesh/g_values.cxx @@ -0,0 +1,26 @@ +#include "bout/g_values.hxx" +#include "bout/coordinates.hxx" +#include "bout/derivs.hxx" +#include "bout/mesh.hxx" +#include "bout/metric_tensor.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* mesh = J.getMesh(); + + G1_m = (DDX(J * g11) + DDY(J.asField3DParallel() * g12) + DDZ(J * g13)) / J; + G2_m = (DDX(J * g12) + DDY(J.asField3DParallel() * g22) + DDZ(J * g23)) / J; + G3_m = (DDX(J * g13) + DDY(J.asField3DParallel() * g23) + DDZ(J * g33)) / J; + + mesh->communicate_no_slices(G1_m, G2_m, G3_m); +} diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 33368e6d6a..c8367f3541 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -1,3 +1,4 @@ +#include "bout/assert.hxx" #include #include #include @@ -554,12 +555,39 @@ 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); +} + +std::shared_ptr Mesh::getCoordinatesSmart(CELL_LOC location) { + ASSERT1(location != CELL_DEFAULT); + ASSERT1(location != CELL_VSHIFT); + + auto found = coords_map.find(location); + if (found != coords_map.end()) { + // True branch most common, returns immediately + return found->second; + } + + // No coordinate system set. Create default + // 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); + 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; } const Region<>& Mesh::getRegion3D(const std::string& region_name) const { @@ -772,8 +800,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); + + auto recalculate_staggered = false; + new_coordinates.recalculateAndReset(recalculate_staggered, + force_interpolate_from_centre); + *coords_map[location] = std::move(new_coordinates); } } diff --git a/src/mesh/metric_tensor.cxx b/src/mesh/metric_tensor.cxx new file mode 100644 index 0000000000..5444f538d3 --- /dev/null +++ b/src/mesh/metric_tensor.cxx @@ -0,0 +1,154 @@ +#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"); + // Check off-diagonal separately, might not have them even if we have parallel + // slices for the diagonal components + if (g23_m.hasParallelSlices() && &g23_m.ynext(1) != &g23_m) { + 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); + } + } + } +} + +namespace { +template +auto inverse_impl(const MetricTensor& metric, const std::string& region) + -> InverseMetric { + // Perform inversion of g{ij} to get g^{ij}, or vice versa + auto matrix = Matrix(3, 3); + + bout::FieldMetric g_11 = emptyFrom(metric.g11()); + bout::FieldMetric g_22 = emptyFrom(metric.g22()); + bout::FieldMetric g_33 = emptyFrom(metric.g33()); + bout::FieldMetric g_12 = emptyFrom(metric.g12()); + bout::FieldMetric g_13 = emptyFrom(metric.g13()); + bout::FieldMetric g_23 = emptyFrom(metric.g23()); + + BOUT_FOR_SERIAL(i, metric.g11().getRegion(region)) { + matrix(0, 0) = metric.g11()[i]; + matrix(1, 1) = metric.g22()[i]; + matrix(2, 2) = metric.g33()[i]; + + matrix(0, 1) = matrix(1, 0) = metric.g12()[i]; + matrix(1, 2) = matrix(2, 1) = metric.g23()[i]; + matrix(0, 2) = matrix(2, 0) = metric.g13()[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); + return InverseMetric(g_11, g_22, g_33, g_12, g_13, g_23); +} +} // namespace + +auto CovariantMetricTensor::inverse(const std::string& region, bool communicate) + -> ContravariantMetricTensor { + auto result = inverse_impl(*this, region); + if (communicate) { + result.communicate(); + } + return result; +} + +auto ContravariantMetricTensor::inverse(const std::string& region, bool communicate) + -> CovariantMetricTensor { + auto result = inverse_impl(*this, region); + if (communicate) { + result.communicate(); + } + return result; +} + +void MetricTensor::communicate() { + g11_m.getMesh()->communicate_no_slices(g11_m, g22_m, g33_m, g12_m, g13_m, g23_m); +} diff --git a/src/mesh/parallel/fci.cxx b/src/mesh/parallel/fci.cxx index aebfeb654c..72861eb68f 100644 --- a/src/mesh/parallel/fci.cxx +++ b/src/mesh/parallel/fci.cxx @@ -42,10 +42,11 @@ #include "bout/boundary_region_iter.hxx" #include "bout/bout_types.hxx" #include "bout/boutexception.hxx" -#include "bout/build_defines.hxx" +#include "bout/coordinates.hxx" #include "bout/field2d.hxx" #include "bout/field3d.hxx" #include "bout/field_data.hxx" +#include "bout/interpolation_xz.hxx" #include "bout/mesh.hxx" #include "bout/msg_stack.hxx" #include "bout/options.hxx" @@ -62,61 +63,9 @@ #include #include #include -#include -using namespace std::string_view_literals; using bout::boundary::BoundaryRegionFCI; -namespace { -// Get a unique name for a field based on the sign/magnitude of the offset -std::string parallel_slice_field_name(const std::string& field, int offset) { - const std::string direction = (offset > 0) ? "forward" : "backward"; - // We only have a suffix for parallel slices beyond the first - // This is for backwards compatibility - const std::string slice_suffix = - (std::abs(offset) > 1) ? "_" + std::to_string(std::abs(offset)) : ""; - return direction + "_" + field + slice_suffix; -}; - -#if BOUT_USE_METRIC_3D -void load_parallel_metric_component(std::string name, Field3D& component, int offset) { - Mesh* mesh = component.getMesh(); - Field3D tmp{mesh}; - const auto pname = parallel_slice_field_name(name, offset); - if (mesh->get(tmp, pname, 0.0, false) != 0) { - throw BoutException("Could not read {:s} from grid file!\n" - " Fix it up with `zoidberg-update-parallel-metrics `", - pname); - } - if (!component.hasParallelSlices()) { - component.splitParallelSlices(); - component.disallowCalcParallelSlices(); - component.resetRegionParallel(true); - } - auto& pcom = component.ynext(offset); - pcom.allocate(); - BOUT_FOR(i, component.getRegion("RGN_NOBNDRY")) { pcom[i.yp(offset)] = tmp[i]; } -} - -void load_parallel_metric_components(Coordinates* coords, int offset) { -#define LOAD_PAR(var) load_parallel_metric_component(#var, coords->var, offset) - LOAD_PAR(g11); - LOAD_PAR(g22); - LOAD_PAR(g33); - LOAD_PAR(g13); - LOAD_PAR(g_11); - LOAD_PAR(g_22); - LOAD_PAR(g_33); - LOAD_PAR(g_13); - LOAD_PAR(dy); - LOAD_PAR(Bxy); - -#undef LOAD_PAR -} -#endif - -} // namespace - FCIMap::FCIMap(Mesh& mesh, [[maybe_unused]] const Coordinates::FieldMetric& dy, Options& options, int offset, const std::shared_ptr& inner_boundary, @@ -155,29 +104,31 @@ FCIMap::FCIMap(Mesh& mesh, [[maybe_unused]] const Coordinates::FieldMetric& dy, map_mesh->get(R, "R", 0.0, false); map_mesh->get(Z, "Z", 0.0, false); + using bout::parallelSliceFieldName; + // If we can't read in any of these fields, things will silently not // work, so best throw - if (map_mesh->get(xt_prime, parallel_slice_field_name("xt_prime", offset), 0.0, false) + if (map_mesh->get(xt_prime, parallelSliceFieldName("xt_prime", offset), 0.0, false) != 0) { throw BoutException("Could not read {:s} from grid file!\n" " Either add it to the grid file, or reduce MYG", - parallel_slice_field_name("xt_prime", offset)); + parallelSliceFieldName("xt_prime", offset)); } - if (map_mesh->get(zt_prime, parallel_slice_field_name("zt_prime", offset), 0.0, false) + if (map_mesh->get(zt_prime, parallelSliceFieldName("zt_prime", offset), 0.0, false) != 0) { throw BoutException("Could not read {:s} from grid file!\n" " Either add it to the grid file, or reduce MYG", - parallel_slice_field_name("zt_prime", offset)); + parallelSliceFieldName("zt_prime", offset)); } - if (map_mesh->get(R_prime, parallel_slice_field_name("R", offset), 0.0, false) != 0) { + if (map_mesh->get(R_prime, parallelSliceFieldName("R", offset), 0.0, false) != 0) { throw BoutException("Could not read {:s} from grid file!\n" " Either add it to the grid file, or reduce MYG", - parallel_slice_field_name("R", offset)); + parallelSliceFieldName("R", offset)); } - if (map_mesh->get(Z_prime, parallel_slice_field_name("Z", offset), 0.0, false) != 0) { + if (map_mesh->get(Z_prime, parallelSliceFieldName("Z", offset), 0.0, false) != 0) { throw BoutException("Could not read {:s} from grid file!\n" " Either add it to the grid file, or reduce MYG", - parallel_slice_field_name("Z", offset)); + parallelSliceFieldName("Z", offset)); } // Cell corners @@ -467,24 +418,3 @@ void FCITransform::outputVars(Options& output_options) { output_options["R"].force(R, "FCI"); output_options["Z"].force(Z, "FCI"); } - -void FCITransform::loadParallelMetrics([[maybe_unused]] Coordinates* coords) { -#if BOUT_USE_METRIC_3D - output_info.write("\tLoading parallel metrics\n"); - const Coordinates::FieldMetric JB0 = coords->J * coords->Bxy; - coords->J.splitParallelSlices(); - coords->J.disallowCalcParallelSlices(); - coords->J.resetRegionParallel(true); - for (int i = 1; i <= mesh.ystart; ++i) { - load_parallel_metric_components(coords, -i); - load_parallel_metric_components(coords, i); - - coords->J.ynext(i).allocate(); - coords->J.ynext(-i).allocate(); - BOUT_FOR(j, JB0.getRegion("RGN_NOBNDRY")) { - coords->J.ynext(i)[j.yp(i)] = JB0[j] / coords->Bxy.ynext(i)[j.yp(i)]; - coords->J.ynext(-i)[j.yp(-i)] = JB0[j] / coords->Bxy.ynext(-i)[j.yp(-i)]; - } - } -#endif -} diff --git a/src/mesh/parallel/fci.hxx b/src/mesh/parallel/fci.hxx index a90e3e98dd..f5d0642675 100644 --- a/src/mesh/parallel/fci.hxx +++ b/src/mesh/parallel/fci.hxx @@ -126,8 +126,6 @@ public: return false; } - void loadParallelMetrics(Coordinates* coords) override; - protected: void checkInputGrid() override; diff --git a/src/mesh/petsc_operators.cxx b/src/mesh/petsc_operators.cxx index 573044a0a1..42a35fbf5d 100644 --- a/src/mesh/petsc_operators.cxx +++ b/src/mesh/petsc_operators.cxx @@ -333,14 +333,15 @@ PetscOperators::Parallel PetscOperators::getParallel() const { auto* coords = mesh->getCoordinates(); // Parallel spacing in cell space - Field3D dl = Coordinates::FieldMetric{coords->dy * sqrt(coords->g_22)}; + Field3D dl = Coordinates::FieldMetric{coords->dy() * sqrt(coords->g_22())}; dl.splitParallelSlices(); dl.yup() = 0.0; dl.ydown() = 0.0; dl.applyParallelBoundary("parallel_neumann_o1"); // Cell volume - Field3D dV = Coordinates::FieldMetric{coords->J * coords->dx * coords->dy * coords->dz}; + Field3D dV = + Coordinates::FieldMetric{coords->J() * coords->dx() * coords->dy() * coords->dz()}; dV.splitParallelSlices(); dV.yup() = 0.0; dV.ydown() = 0.0; diff --git a/src/mesh/tokamak_coordinates.cxx b/src/mesh/tokamak_coordinates.cxx index af8b6335bf..06e38155f0 100644 --- a/src/mesh/tokamak_coordinates.cxx +++ b/src/mesh/tokamak_coordinates.cxx @@ -2,37 +2,38 @@ #include #include #include +#include #include #include namespace bout { TokamakCoordinates set_tokamak_coordinates(Mesh& mesh, BoutReal Lbar, BoutReal Bbar, bool no_shear, BoutReal shear_factor) { - Field2D Rxy; + FieldMetric Rxy; mesh.get(Rxy, "Rxy"); // [m] Rxy /= Lbar; - Field2D Zxy; + FieldMetric Zxy; mesh.get(Zxy, "Zxy"); // [m] Zxy /= Lbar; - Field2D Bpxy; + FieldMetric Bpxy; mesh.get(Bpxy, "Bpxy"); // [T] Bpxy /= Bbar; - Field2D Btxy; + FieldMetric Btxy; mesh.get(Btxy, "Btxy"); // [T] Btxy /= Bbar; - Field2D Bxy; + FieldMetric Bxy; mesh.get(Bxy, "Bxy"); // [T] Bxy /= Bbar; - Field2D hthe; + FieldMetric hthe; mesh.get(hthe, "hthe"); // [m / radian] hthe /= Lbar; - Coordinates::FieldMetric I; + bout::FieldMetric I; if (no_shear) { I = 0.0; } else { @@ -41,36 +42,36 @@ TokamakCoordinates set_tokamak_coordinates(Mesh& mesh, BoutReal Lbar, BoutReal B const auto I_unnormalised = I; I *= Lbar * Lbar * Bbar * shear_factor; - Coordinates::FieldMetric dx; + bout::FieldMetric dx; if (mesh.get(dx, "dpsi") != 0) { - dx = mesh.getCoordinates()->dx; + dx = mesh.getCoordinates()->dx(); } dx /= Lbar * Lbar * Bbar; const BoutReal sign_of_bp = min(Bpxy, true) < 0.0 ? -1.0 : 1.0; - auto* coords = mesh.getCoordinates(); + auto* coord = mesh.getCoordinates(); - coords->Bxy = Bxy; - coords->dx = dx; + const FieldMetric g11 = SQ(Rxy * Bpxy); + const FieldMetric g22 = 1.0 / SQ(hthe); + const FieldMetric g33 = SQ(I) * g11 + SQ(Bxy) / g11; + const FieldMetric g12 = 0.0; + const FieldMetric g13 = -I * g11; + const FieldMetric g23 = -sign_of_bp * Btxy / (hthe * Bpxy * Rxy); - coords->g11 = SQ(Rxy * Bpxy); - coords->g22 = 1.0 / SQ(hthe); - coords->g33 = SQ(I) * coords->g11 + SQ(Bxy) / coords->g11; - coords->g12 = 0.0; - coords->g13 = -I * coords->g11; - coords->g23 = -sign_of_bp * Btxy / (hthe * Bpxy * Rxy); + const FieldMetric g_11 = 1.0 / g11 + SQ(I * Rxy); + const FieldMetric g_22 = SQ(Bxy * hthe / Bpxy); + const FieldMetric g_33 = Rxy * Rxy; + const FieldMetric g_12 = sign_of_bp * Btxy * hthe * I * Rxy / Bpxy; + const FieldMetric g_13 = I * Rxy * Rxy; + const FieldMetric g_23 = sign_of_bp * Btxy * hthe * Rxy / Bpxy; - coords->J = hthe / Bpxy; + coord->setMetricTensor(ContravariantMetricTensor(g11, g22, g33, g12, g13, g23), + CovariantMetricTensor(g_11, g_22, g_33, g_12, g_13, g_23)); - coords->g_11 = 1.0 / coords->g11 + SQ(I * Rxy); - coords->g_22 = SQ(Bxy * hthe / Bpxy); - coords->g_33 = Rxy * Rxy; - coords->g_12 = sign_of_bp * Btxy * hthe * I * Rxy / Bpxy; - coords->g_13 = I * Rxy * Rxy; - coords->g_23 = sign_of_bp * Btxy * hthe * Rxy / Bpxy; - - coords->geometry(); + coord->setJ(FieldMetric{hthe / Bpxy}); + coord->setBxy(Bxy); + coord->setDx(dx); return {Rxy, Zxy, Bpxy, Btxy, Bxy, hthe, I, I_unnormalised}; } 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 e449dbcd30..b41b83900a 100644 --- a/src/sys/derivs.cxx +++ b/src/sys/derivs.cxx @@ -41,17 +41,16 @@ #include #include #include -#include #include #include #include #include #include #include +#include #include -#include +#include #include -#include #include @@ -63,12 +62,23 @@ Field3D DDX(const Field3D& f, CELL_LOC outloc, const std::string& method, const std::string& region) { - return f.getCoordinates(outloc)->DDX(f, outloc, method, region); + const auto& coords = *f.getCoordinates(outloc); + + Field3D result = bout::derivatives::index::DDX(f, outloc, method, region) / coords.dx(); + + if (f.getMesh()->IncIntShear) { + // Using BOUT-06 style shifting + result += coords.IntShiftTorsion() * DDZ(f, outloc, method, region); + } + + return result; } -Coordinates::FieldMetric DDX(const Field2D& f, CELL_LOC outloc, const std::string& method, - const std::string& region) { - return f.getCoordinates(outloc)->DDX(f, outloc, method, region); +bout::FieldMetric DDX(const Field2D& f, CELL_LOC outloc, const std::string& method, + const std::string& region) { + ASSERT1(f.getLocation() == outloc || outloc == CELL_DEFAULT); + return bout::derivatives::index::DDX(f, outloc, method, region) + / f.getCoordinates(outloc)->dx(); } ////////////// Y DERIVATIVE ///////////////// @@ -76,12 +86,14 @@ Coordinates::FieldMetric DDX(const Field2D& f, CELL_LOC outloc, const std::strin Field3D DDY(const Field3DParallel& 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, - const std::string& region) { - return f.getCoordinates(outloc)->DDY(f, outloc, method, region); +bout::FieldMetric DDY(const Field2D& f, CELL_LOC outloc, const std::string& method, + const std::string& region) { + ASSERT1(f.getLocation() == outloc || outloc == CELL_DEFAULT); + return bout::derivatives::index::DDY(f, outloc, method, region) + / f.getCoordinates(outloc)->dy(); } ////////////// Z DERIVATIVE ///////////////// @@ -89,12 +101,12 @@ 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), - const std::string& UNUSED(method), - const std::string& UNUSED(region)) { +bout::FieldMetric DDZ(const Field2D& f, CELL_LOC UNUSED(outloc), + const std::string& UNUSED(method), + const std::string& UNUSED(region)) { auto tmp = Field2D(0., f.getMesh()); tmp.setLocation(f.getLocation()); return tmp; @@ -107,21 +119,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; } @@ -158,12 +170,13 @@ Field3D D2DX2(const Field3D& f, CELL_LOC outloc, const std::string& method, const 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())) @@ -172,17 +185,18 @@ Field3D D2DX2(const Field3D& f, CELL_LOC outloc, const std::string& method, return result; } -Coordinates::FieldMetric D2DX2(const Field2D& f, CELL_LOC outloc, - const std::string& method, const std::string& region) { +bout::FieldMetric D2DX2(const Field2D& f, CELL_LOC outloc, const std::string& method, + const std::string& region) { const Coordinates* coords = f.getCoordinates(outloc); - Coordinates::FieldMetric result = - bout::derivatives::index::D2DX2(f, outloc, method, region) / SQ(coords->dx); + bout::FieldMetric result = + 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; @@ -195,12 +209,13 @@ Field3D D2DY2(const Field3D& f, CELL_LOC outloc, const std::string& method, const 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())) @@ -209,16 +224,17 @@ Field3D D2DY2(const Field3D& f, CELL_LOC outloc, const std::string& method, return result; } -Coordinates::FieldMetric D2DY2(const Field2D& f, CELL_LOC outloc, - const std::string& method, const std::string& region) { +bout::FieldMetric D2DY2(const Field2D& f, CELL_LOC outloc, const std::string& method, + const std::string& region) { const Coordinates* coords = f.getCoordinates(outloc); - Coordinates::FieldMetric result = - bout::derivatives::index::D2DY2(f, outloc, method, region) / SQ(coords->dy); - if (coords->non_uniform) { + bout::FieldMetric result = + 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; @@ -229,13 +245,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) { +bout::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()); } /******************************************************************************* @@ -245,37 +261,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) { +bout::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) { +bout::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) { +bout::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())); } /******************************************************************************* @@ -289,10 +305,10 @@ Coordinates::FieldMetric D4DZ4(const Field2D& f, CELL_LOC outloc, * * ** Communicates and applies boundary in X. */ -Coordinates::FieldMetric D2DXDY(const Field2D& f, CELL_LOC outloc, - const std::string& method, const std::string& region, - const std::string& dfdy_boundary_condition, - const std::string& dfdy_region) { +bout::FieldMetric D2DXDY(const Field2D& f, CELL_LOC outloc, const std::string& method, + const std::string& region, + const std::string& dfdy_boundary_condition, + const std::string& dfdy_region) { const std::string dy_region = dfdy_region.empty() ? region : dfdy_region; // If staggering in x, take y-derivative at f's location. @@ -333,9 +349,9 @@ Field3D D2DXDY(const Field3D& f, CELL_LOC outloc, const std::string& method, return DDX(dfdy, outloc, method, region); } -Coordinates::FieldMetric D2DXDZ(const Field2D& f, CELL_LOC outloc, - [[maybe_unused]] const std::string& method, - [[maybe_unused]] const std::string& region) { +bout::FieldMetric D2DXDZ(const Field2D& f, CELL_LOC outloc, + [[maybe_unused]] const std::string& method, + [[maybe_unused]] const std::string& region) { #if BOUT_USE_METRIC_3D Field3D tmp{f}; return D2DXDZ(tmp, outloc, method, region); @@ -358,9 +374,9 @@ Field3D D2DXDZ(const Field3D& f, CELL_LOC outloc, const std::string& method, return DDZ(DDX(f, x_location, method, region), outloc, method, region); } -Coordinates::FieldMetric D2DYDZ(const Field2D& f, CELL_LOC outloc, - [[maybe_unused]] const std::string& method, - [[maybe_unused]] const std::string& region) { +bout::FieldMetric D2DYDZ(const Field2D& f, CELL_LOC outloc, + [[maybe_unused]] const std::string& method, + [[maybe_unused]] const std::string& region) { #if BOUT_USE_METRIC_3D Field3D tmp{f}; return D2DYDZ(tmp, outloc, method, region); @@ -390,52 +406,52 @@ Field3D D2DYDZ(const Field3D& f, CELL_LOC outloc, ////////////// X DERIVATIVE ///////////////// /// Special case where both arguments are 2D. -Coordinates::FieldMetric VDDX(const Field2D& v, const Field2D& f, CELL_LOC outloc, - const std::string& method, const std::string& region) { +bout::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 ///////////////// // special case where both are 2D -Coordinates::FieldMetric VDDY(const Field2D& v, const Field2D& f, CELL_LOC outloc, - const std::string& method, const std::string& region) { +bout::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 Field3DParallel& 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 ///////////////// // special case where both are 2D -Coordinates::FieldMetric VDDZ(const Field2D& v, const Field2D& f, CELL_LOC outloc, - const std::string& method, const std::string& region) { +bout::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 -Coordinates::FieldMetric VDDZ([[maybe_unused]] const Field3D& v, const Field2D& f, - CELL_LOC outloc, [[maybe_unused]] const std::string& method, - [[maybe_unused]] const std::string& region) { +bout::FieldMetric VDDZ([[maybe_unused]] const Field3D& v, const Field2D& f, + CELL_LOC outloc, [[maybe_unused]] const std::string& method, + [[maybe_unused]] const std::string& region) { #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(); @@ -448,48 +464,48 @@ 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(); } /******************************************************************************* * Flux conserving schemes *******************************************************************************/ -Coordinates::FieldMetric FDDX(const Field2D& v, const Field2D& f, CELL_LOC outloc, - const std::string& method, const std::string& region) { +bout::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(); } ///////////////////////////////////////////////////////////////////////// -Coordinates::FieldMetric FDDY(const Field2D& v, const Field2D& f, CELL_LOC outloc, - const std::string& method, const std::string& region) { +bout::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 Field3DParallel& 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(); } ///////////////////////////////////////////////////////////////////////// -Coordinates::FieldMetric FDDZ(const Field2D& v, const Field2D& f, CELL_LOC outloc, - const std::string& method, const std::string& region) { +bout::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 6d7fbcafd2..e2c42ead65 100644 --- a/tests/MMS/GBS/gbs.cxx +++ b/tests/MMS/GBS/gbs.cxx @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -281,7 +282,7 @@ int GBS::init(bool restarting) { break; } case 3: { // logB, taken from mesh - logB = log(coords->Bxy); + logB = log(coords->Bxy()); break; } default: @@ -292,14 +293,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); + 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)); @@ -369,7 +370,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 { @@ -382,7 +383,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 { @@ -396,8 +398,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) { @@ -414,7 +416,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); @@ -438,14 +440,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)); } } @@ -481,7 +483,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/advection/advection.cxx b/tests/MMS/advection/advection.cxx index 1201fbc3ac..2480fdb8c6 100644 --- a/tests/MMS/advection/advection.cxx +++ b/tests/MMS/advection/advection.cxx @@ -4,6 +4,7 @@ */ #include +#include #include #include @@ -18,8 +19,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..3353767e35 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,8 @@ 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(); + coord->setMetricTensor(ContravariantMetricTensor(1.0, 1.0, 1.0, 0.0, 0.0, 0.0), + CovariantMetricTensor(1.0, 1.0, 1.0, 0.0, 0.0, 0.0)); // Tell BOUT++ to solve N SOLVE_FOR(N); diff --git a/tests/MMS/diffusion2/diffusion.cxx b/tests/MMS/diffusion2/diffusion.cxx index bd2cd72a08..50313fcd2a 100644 --- a/tests/MMS/diffusion2/diffusion.cxx +++ b/tests/MMS/diffusion2/diffusion.cxx @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -21,9 +22,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 +39,8 @@ 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(); + coords->setMetricTensor(ContravariantMetricTensor(1.0, 1.0, 1.0, 0.0, 0.0, 0.0), + CovariantMetricTensor(1.0, 1.0, 1.0, 0.0, 0.0, 0.0)); // 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 8fb2a58cbf..f678f89aac 100644 --- a/tests/MMS/elm-pb/elm_pb.cxx +++ b/tests/MMS/elm-pb/elm_pb.cxx @@ -292,7 +292,7 @@ class ELMpb : public PhysicsModel { const auto& hthe = tokamak_coords.hthe; const auto& I = tokamak_coords.I_unnormalised; - B0 = tokamak_coords.Bxy; + B0 = tokamak_coords.Bxy(); if (include_curvature) { // Load curvature term @@ -315,7 +315,7 @@ class ELMpb : public PhysicsModel { if (ShiftXderivs) { if (mesh->IncIntShear) { // BOUT-06 style, using d/dx = d/dpsi + I * d/dz - mesh->getCoordinates()->IntShiftTorsion = I; + mesh->getCoordinates()->setIntShiftTorsion(I); } else { // Dimits style, using local coordinate system if (include_curvature) { @@ -596,7 +596,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 @@ -616,7 +616,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..c5574f26b0 100644 --- a/tests/MMS/fieldalign/fieldalign.cxx +++ b/tests/MMS/fieldalign/fieldalign.cxx @@ -1,4 +1,5 @@ #include +#include #include class FieldAlign : public PhysicsModel { @@ -20,14 +21,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..0050cd2bcf 100644 --- a/tests/MMS/spatial/diffusion/diffusion.cxx +++ b/tests/MMS/spatial/diffusion/diffusion.cxx @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -22,9 +23,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)); @@ -39,20 +40,8 @@ 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(); + coords->setMetricTensor(ContravariantMetricTensor(1.0, 1.0, 1.0, 0.0, 0.0, 0.0), + CovariantMetricTensor(1.0, 1.0, 1.0, 0.0, 0.0, 0.0)); // Tell BOUT++ to solve N SOLVE_FOR(N); diff --git a/tests/MMS/tokamak/tokamak.cxx b/tests/MMS/tokamak/tokamak.cxx index 8b6baab950..9648ddf7f5 100644 --- a/tests/MMS/tokamak/tokamak.cxx +++ b/tests/MMS/tokamak/tokamak.cxx @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -34,8 +35,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); diff --git a/tests/MMS/wave-1d/wave.cxx b/tests/MMS/wave-1d/wave.cxx index 4f53d098c6..b5cc343297 100644 --- a/tests/MMS/wave-1d/wave.cxx +++ b/tests/MMS/wave-1d/wave.cxx @@ -1,6 +1,8 @@ #include #include +#include #include +#include #include #include #include @@ -26,26 +28,14 @@ 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(); + coord->setMetricTensor(ContravariantMetricTensor(1.0, 1.0, 1.0, 0.0, 0.0, 0.0), + CovariantMetricTensor(1.0, 1.0, 1.0, 0.0, 0.0, 0.0)); 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 dca5a69e3b..7af5834e8c 100644 --- a/tests/integrated/test-drift-instability/2fluid.cxx +++ b/tests/integrated/test-drift-instability/2fluid.cxx @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -14,7 +15,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 @@ -368,7 +369,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 db0fef2fbf..3909093007 100644 --- a/tests/integrated/test-interchange-instability/2fluid.cxx +++ b/tests/integrated/test-interchange-instability/2fluid.cxx @@ -142,10 +142,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/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..81688eb135 100644 --- a/tests/integrated/test-laplacexz/test-laplacexz.cxx +++ b/tests/integrated/test-laplacexz/test-laplacexz.cxx @@ -9,30 +9,39 @@ * -mat_superlu_dist_statprint */ #include - #include +#include +#include #include +#include #include +#include +#include +#include int main(int argc, char** argv) { BoutInitialise(argc, 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 + auto* coord = bout::globals::mesh->getCoordinates(); + // test off-diagonal components with nonzero value + coord->setContravariantMetricTensor({1.0, 1.0, 1.0, 0.1, 0.8, 0.1}); // create some input field - Field3D f = FieldFactory::get()->create3D("f", Options::getRoot(), bout::globals::mesh); + const 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. + const 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({1.0, 1.0, 1.0, 0.0, 0.0, 0.0}); // Now the normal test. output.write("Setting coefficients\n"); @@ -41,17 +50,17 @@ int main(int argc, char** argv) { output.write("First solve\n"); - Field3D rhs = + const Field3D rhs = FieldFactory::get()->create3D("rhs", Options::getRoot(), bout::globals::mesh); - Field3D x = inv->solve(rhs, 0.0); + const Field3D x = inv->solve(rhs, 0.0); output.write("Second solve\n"); inv->setCoefs(Field3D(2.0), Field3D(0.1)); - Field3D rhs2 = + const Field3D rhs2 = FieldFactory::get()->create3D("rhs", Options::getRoot(), bout::globals::mesh); - Field3D x2 = inv->solve(rhs2, 0.0); + const Field3D x2 = inv->solve(rhs2, 0.0); Options dump; 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-petsc-operators/test_petsc_operators.cxx b/tests/integrated/test-petsc-operators/test_petsc_operators.cxx index 6c70c65f39..2d41d0ae0a 100644 --- a/tests/integrated/test-petsc-operators/test_petsc_operators.cxx +++ b/tests/integrated/test-petsc-operators/test_petsc_operators.cxx @@ -50,7 +50,6 @@ int main(int argc, char** argv) { dump["div_par_op"] = parallel.Div_par(f); auto* coords = bout::globals::mesh->getCoordinates(); - coords->Bxy.applyParallelBoundary("parallel_neumann_o1"); dump["div_par_yud"] = Div_par(f); dump["div_par_grad_par_op"] = parallel.Div_par_Grad_par(f_neumann); diff --git a/tests/integrated/test-snb/test_snb.cxx b/tests/integrated/test-snb/test_snb.cxx index 1b96bfc8b1..40dfd4880d 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 @@ -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; @@ -228,8 +234,8 @@ int main(int argc, char** argv) { // Check that fluxes are not equal 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; diff --git a/tests/unit/fake_mesh_fixture.hxx b/tests/unit/fake_mesh_fixture.hxx index 2758dbe416..da1b65cb87 100644 --- a/tests/unit/fake_mesh_fixture.hxx +++ b/tests/unit/fake_mesh_fixture.hxx @@ -3,11 +3,14 @@ #include #include +#include "bout/build_config.hxx" +#include "bout/metric_tensor.hxx" #include #include #include #include #include +#include #include #include #include @@ -47,22 +50,22 @@ public: 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; + mesh_m.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; -#if BOUT_USE_METRIC_3D - test_coords->Bxy.splitParallelSlices(); - test_coords->Bxy.yup() = test_coords->Bxy.ydown() = test_coords->Bxy; -#endif - - // No call to Coordinates::geometry() needed here + 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::build::use_metric_3d) { + bout::FieldMetric mutable_Bxy = test_coords->Bxy(); + mutable_Bxy.splitParallelSlices(); + mutable_Bxy.yup() = test_coords->Bxy(); + mutable_Bxy.ydown() = test_coords->Bxy(); + test_coords->setBxy(mutable_Bxy); + } + mesh_m.setCoordinates(test_coords); mesh_m.setGridDataSource(new FakeGridDataSource()); // May need a ParallelTransform to create fields, because create3D calls @@ -89,22 +92,25 @@ public: 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_m.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; -#if BOUT_USE_METRIC_3D - test_coords_staggered->Bxy.splitParallelSlices(); - test_coords_staggered->Bxy.yup() = test_coords_staggered->Bxy.ydown() = - test_coords_staggered->Bxy; -#endif - - // No call to Coordinates::geometry() needed here + 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::build::use_metric_3d) { + bout::FieldMetric 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); + } + test_coords_staggered->setParallelTransform( bout::utils::make_unique(mesh_staggered_m)); diff --git a/tests/unit/fake_parallel_mesh.hxx b/tests/unit/fake_parallel_mesh.hxx index f679963064..bc2892db53 100644 --- a/tests/unit/fake_parallel_mesh.hxx +++ b/tests/unit/fake_parallel_mesh.hxx @@ -265,7 +265,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 9db9fcef10..38ca612521 100644 --- a/tests/unit/field/test_field_factory.cxx +++ b/tests/unit/field/test_field_factory.cxx @@ -565,8 +565,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 d99d2ed179..354b6b85ad 100644 --- a/tests/unit/field/test_vector2d.cxx +++ b/tests/unit/field/test_vector2d.cxx @@ -42,7 +42,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 5b197d5cdf..68977e2228 100644 --- a/tests/unit/field/test_vector3d.cxx +++ b/tests/unit/field/test_vector3d.cxx @@ -41,7 +41,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 586dd80adf..c01488a320 100644 --- a/tests/unit/invert/laplace/test_laplace_cyclic.cxx +++ b/tests/unit/invert/laplace/test_laplace_cyclic.cxx @@ -34,7 +34,7 @@ class CyclicForwardOperator { Field3D operator()(Field3D& f) { Field3D result = d * Delp2(f) - + (coords->g11 * DDX(f) + coords->g13 * DDZ(f)) * DDX(c2) / c1 + + (coords->g11() * DDX(f) + coords->g13() * DDZ(f)) * DDX(c2) / c1 + a * f + ex * DDX(f) + ez * DDZ(f); applyBoundaries(result, f); return result; @@ -47,7 +47,7 @@ class CyclicForwardOperator { void applyBoundaries(Field3D& newF, const Field3D& f) const { 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()]); } @@ -55,7 +55,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]); } @@ -79,7 +79,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 a721b96833..e0febdbb22 100644 --- a/tests/unit/invert/laplace/test_laplace_hypre3d.cxx +++ b/tests/unit/invert/laplace/test_laplace_hypre3d.cxx @@ -40,8 +40,8 @@ class ForwardOperator { const Field3D operator()(Field3D& f) { Field3D result = d * Laplace_perp(f, CELL_DEFAULT, "free", "RGN_NOY") - + (Grad(f) * Grad(c2) - DDY(c2) * DDY(f) / coords->g_22) / c1 + a * f - + ex * DDX(f) + ez * DDZ(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 846cb9107f..dcb5e74b31 100644 --- a/tests/unit/invert/laplace/test_laplace_petsc3damg.cxx +++ b/tests/unit/invert/laplace/test_laplace_petsc3damg.cxx @@ -40,8 +40,8 @@ class ForwardOperator { const Field3D operator()(Field3D& f) { Field3D result = d * Laplace_perp(f, CELL_DEFAULT, "free", "RGN_NOY") - + (Grad(f) * Grad(c2) - DDY(c2) * DDY(f) / coords->g_22) / c1 + a * f - + ex * DDX(f) + ez * DDZ(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..9b1fb9410b 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. @@ -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) { @@ -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) { @@ -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 } @@ -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 8e1aa2e13f..05f77d0c98 100644 --- a/tests/unit/mesh/test_coordinates.cxx +++ b/tests/unit/mesh/test_coordinates.cxx @@ -1,4 +1,5 @@ #include "gtest/gtest.h" +#include #include "bout/build_defines.hxx" #include "bout/constants.hxx" @@ -6,6 +7,7 @@ #include "bout/mesh.hxx" #include "bout/output.hxx" +#include "fake_mesh.hxx" #include "fake_mesh_fixture.hxx" #include "test_extras.hxx" @@ -42,7 +44,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 +76,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 +102,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 +132,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 +165,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, "RGN_NOCORNERS")); + EXPECT_TRUE(IsFieldEqual(coords.Bxy(), 1.0, "RGN_NOCORNERS")); } TEST_F(CoordinatesTest, ConstructWithMeshSpacing) { @@ -204,58 +202,58 @@ 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, "RGN_NOCORNERS")); + EXPECT_TRUE(IsFieldEqual(coords.Bxy(), 1.0, "RGN_NOCORNERS")); } 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) { - static_cast(bout::globals::mesh) - ->setGridDataSource( - new FakeGridDataSource({{"g11", 2.0}, {"g22", 3.2}, {"g33", 42}})); + dynamic_cast(mesh)->setGridDataSource( + new FakeGridDataSource({{"g11", 2.0}, {"g22", 3.2}, {"g33", 42}})); - Coordinates coords(mesh); + const 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) { @@ -294,21 +292,19 @@ TEST_F(CoordinatesTest, CellAreas) { FieldMetric{0.0}, // g_23 FieldMetric{0.0}, // ShiftTorsion FieldMetric{0.0}}; // IntShiftTorsion - // No call to Coordinates::geometry() needed here - - EXPECT_TRUE(IsFieldEqual(coords.dx, 1.0)); - EXPECT_TRUE(IsFieldEqual(coords.dy, 1.0)); - EXPECT_TRUE(IsFieldEqual(coords.dz, 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.dx(), 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.dy(), 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.dz(), 1.0)); - EXPECT_TRUE(IsFieldEqual(coords.g_11, 4.0)); - EXPECT_TRUE(IsFieldEqual(coords.g_22, 1.0)); - EXPECT_TRUE(IsFieldEqual(coords.g_33, 9.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(), 4.0)); + EXPECT_TRUE(IsFieldEqual(coords.g_22(), 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.g_33(), 9.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.J, 6.0)); - EXPECT_TRUE(IsFieldEqual(coords.Bxy, 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.J(), 6.0)); + EXPECT_TRUE(IsFieldEqual(coords.Bxy(), 1.0)); EXPECT_TRUE(IsFieldEqual(coords.cell_area_xlow(), 3.0, "RGN_NOX")); EXPECT_TRUE(IsFieldEqual(coords.cell_area_xhigh(), 3.0, "RGN_NOX")); @@ -343,19 +339,19 @@ TEST_F(CoordinatesTest, CellAreasUpdate) { FieldMetric{0.0}}; // IntShiftTorsion // No call to Coordinates::geometry() needed here - EXPECT_TRUE(IsFieldEqual(coords.dx, 1.0)); - EXPECT_TRUE(IsFieldEqual(coords.dy, 1.0)); - EXPECT_TRUE(IsFieldEqual(coords.dz, 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.dx(), 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.dy(), 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.dz(), 1.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)); - 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)); coords.cell_area_xlow() *= 2; coords.cell_area_xhigh() *= 3; @@ -401,3 +397,282 @@ TEST_F(CoordinatesTest, CellAreaZComputedAfterCellVolume) { EXPECT_TRUE(IsFieldEqual(coords.cell_area_zlow(), 2.0, "RGN_NOZ")); EXPECT_TRUE(IsFieldEqual(coords.cell_area_zhigh(), 2.0, "RGN_NOZ")); } + +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->zstart; +#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 BoutReal actual_dx = coords.dx(x, y); + const BoutReal actual_dy = coords.dy(x, y); +#else + const BoutReal actual_dx = coords.dx(x, y, z); + const BoutReal actual_dy = coords.dy(x, y, z); + const BoutReal 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..47fde99d17 100644 --- a/tests/unit/mesh/test_coordinates_accessor.cxx +++ b/tests/unit/mesh/test_coordinates_accessor.cxx @@ -1,6 +1,8 @@ #include "gtest/gtest.h" +#include "bout/build_config.hxx" #include "bout/build_defines.hxx" +#include "bout/coordinates.hxx" #include "bout/coordinates_accessor.hxx" #include "fake_mesh_fixture.hxx" @@ -52,41 +54,48 @@ TEST_F(CoordinatesAccessorTest, ClearOneReused) { EXPECT_EQ(CoordinatesAccessor::clear(), 1); } +namespace { +struct TestCoordinates : public Coordinates { + using Coordinates::Coordinates; + using Coordinates::splitBxyParallelSlices; +}; +} // namespace + TEST_F(CoordinatesAccessorTest, ClearBoth) { CoordinatesAccessor::clear(); // Should clear any left over // Make a new Coordinates object to access - Coordinates coords{mesh, - FieldMetric{1.0}, // dx - FieldMetric{1.0}, // dy - FieldMetric{1.0}, // dz - FieldMetric{1.0}, // J - FieldMetric{1.0}, // Bxy - FieldMetric{1.0}, // g11 - FieldMetric{1.0}, // g22 - FieldMetric{1.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 + TestCoordinates coords{mesh, + FieldMetric{1.0}, // dx + FieldMetric{1.0}, // dy + FieldMetric{1.0}, // dz + FieldMetric{1.0}, // J + FieldMetric{1.0}, // Bxy + FieldMetric{1.0}, // g11 + FieldMetric{1.0}, // g22 + FieldMetric{1.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 // 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; -#if BOUT_USE_METRIC_3D - coords.Bxy.splitParallelSlices(); - coords.Bxy.yup() = coords.Bxy.ydown() = coords.Bxy; -#endif + coords.setNon_uniform(true); + coords.setD1_dx(0.1); + coords.setD1_dy(0.1); + coords.setD1_dz(0.1); + if (bout::build::use_metric_3d) { + coords.splitBxyParallelSlices(); + } - CoordinatesAccessor acc(mesh->getCoordinates()); - CoordinatesAccessor acc2(&coords); // Different from previous Coordinates + const CoordinatesAccessor acc(mesh->getCoordinates()); + const CoordinatesAccessor acc2(&coords); // Different from previous Coordinates // Clear both EXPECT_EQ(CoordinatesAccessor::clear(), 2); @@ -96,37 +105,37 @@ TEST_F(CoordinatesAccessorTest, ClearOneTwo) { CoordinatesAccessor::clear(); // Should clear any left over // Make a new Coordinates object to access - Coordinates coords{mesh, - FieldMetric{1.0}, // dx - FieldMetric{1.0}, // dy - FieldMetric{1.0}, // dz - FieldMetric{1.0}, // J - FieldMetric{1.0}, // Bxy - FieldMetric{1.0}, // g11 - FieldMetric{1.0}, // g22 - FieldMetric{1.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 + TestCoordinates coords{mesh, + FieldMetric{1.0}, // dx + FieldMetric{1.0}, // dy + FieldMetric{1.0}, // dz + FieldMetric{1.0}, // J + FieldMetric{1.0}, // Bxy + FieldMetric{1.0}, // g11 + FieldMetric{1.0}, // g22 + FieldMetric{1.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 // 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; -#if BOUT_USE_METRIC_3D - coords.Bxy.splitParallelSlices(); - coords.Bxy.yup() = coords.Bxy.ydown() = coords.Bxy; -#endif + coords.setNon_uniform(true); + coords.setD1_dx(0.1); + coords.setD1_dy(0.1); + coords.setD1_dz(0.1); + if (bout::build::use_metric_3d) { + coords.splitBxyParallelSlices(); + } - CoordinatesAccessor acc(mesh->getCoordinates()); - CoordinatesAccessor acc2(&coords); // Different from previous Coordinates + const CoordinatesAccessor acc(mesh->getCoordinates()); + const CoordinatesAccessor acc2(&coords); // Different from previous Coordinates // clear first one EXPECT_EQ(CoordinatesAccessor::clear(mesh->getCoordinates()), 1); @@ -138,37 +147,37 @@ TEST_F(CoordinatesAccessorTest, ClearTwoOneNone) { CoordinatesAccessor::clear(); // Should clear any left over // Make a new Coordinates object to access - Coordinates coords{mesh, - FieldMetric{1.0}, // dx - FieldMetric{1.0}, // dy - FieldMetric{1.0}, // dz - FieldMetric{1.0}, // J - FieldMetric{1.0}, // Bxy - FieldMetric{1.0}, // g11 - FieldMetric{1.0}, // g22 - FieldMetric{1.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 + TestCoordinates coords{mesh, + FieldMetric{1.0}, // dx + FieldMetric{1.0}, // dy + FieldMetric{1.0}, // dz + FieldMetric{1.0}, // J + FieldMetric{1.0}, // Bxy + FieldMetric{1.0}, // g11 + FieldMetric{1.0}, // g22 + FieldMetric{1.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 // 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; -#if BOUT_USE_METRIC_3D - coords.Bxy.splitParallelSlices(); - coords.Bxy.yup() = coords.Bxy.ydown() = coords.Bxy; -#endif - - CoordinatesAccessor acc(mesh->getCoordinates()); - CoordinatesAccessor acc2(&coords); // Different from previous Coordinates + coords.setNon_uniform(true); + coords.setD1_dx(0.1); + coords.setD1_dy(0.1); + coords.setD1_dz(0.1); + if (bout::build::use_metric_3d) { + coords.splitBxyParallelSlices(); + } + + const CoordinatesAccessor acc(mesh->getCoordinates()); + const CoordinatesAccessor acc2(&coords); // Different from previous Coordinates // clear second one EXPECT_EQ(CoordinatesAccessor::clear(&coords), 1); diff --git a/tests/unit/mesh/test_interpolation.cxx b/tests/unit/mesh/test_interpolation.cxx index d14d54964e..55a385133e 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)); } diff --git a/tools/pylib/_boutpp_build/boutcpp.pxd.jinja b/tools/pylib/_boutpp_build/boutcpp.pxd.jinja index 9de826384b..acb749f9df 100644 --- a/tools/pylib/_boutpp_build/boutcpp.pxd.jinja +++ b/tools/pylib/_boutpp_build/boutcpp.pxd.jinja @@ -68,21 +68,46 @@ cdef extern from "bout/mesh.hxx": cdef extern from "bout/coordinates.hxx": cppclass Coordinates: Coordinates() - {{ metric_field }} dx, dy, dz - {{ metric_field }} J - {{ metric_field }} Bxy - {{ metric_field }} g11, g22, g33, g12, g13, g23 - {{ metric_field }} g_11, g_22, g_33, g_12, g_13, g_23 - {{ metric_field }} G1_11, G1_22, G1_33, G1_12, G1_13, G1_23 - {{ metric_field }} G2_11, G2_22, G2_33, G2_12, G2_13, G2_23 - {{ metric_field }} G3_11, G3_22, G3_33, G3_12, G3_13, G3_23 - {{ 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 + {{ metric_field }} dx() + {{ metric_field }} dy() + {{ metric_field }} dz() + {{ metric_field }} J() + {{ metric_field }} Bxy() + {{ metric_field }} g11() + {{ metric_field }} g22() + {{ metric_field }} g33() + {{ metric_field }} g12() + {{ metric_field }} g13() + {{ metric_field }} g23() + {{ metric_field }} g_11() + {{ metric_field }} g_22() + {{ metric_field }} g_33() + {{ metric_field }} g_12() + {{ metric_field }} g_13() + {{ metric_field }} g_23() + {{ metric_field }} G1_11() + {{ metric_field }} G1_22() + {{ metric_field }} G1_33() + {{ metric_field }} G1_12() + {{ metric_field }} G1_13() + {{ metric_field }} G1_23() + {{ metric_field }} G2_11() + {{ metric_field }} G2_22() + {{ metric_field }} G2_33() + {{ metric_field }} G2_12() + {{ metric_field }} G2_13() + {{ metric_field }} G2_23() + {{ metric_field }} G3_11() + {{ metric_field }} G3_22() + {{ metric_field }} G3_33() + {{ metric_field }} G3_12() + {{ metric_field }} G3_13() + {{ metric_field }} G3_23() + {{ metric_field }} G1() + {{ metric_field }} G2() + {{ metric_field }} G3() + {{ metric_field }} ShiftTorsion() + {{ metric_field }} IntShiftTorsion() 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..f72f6ee95a 100644 --- a/tools/pylib/_boutpp_build/boutpp.pyx.jinja +++ b/tools/pylib/_boutpp_build/boutpp.pyx.jinja @@ -876,7 +876,7 @@ cdef public {{ metric_field }} IntShiftTorsion 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}}) + self.{{f}} = {{ metric_field.fdd }}FromObj(self.cobj.{{f}}()) {% endfor %} {{ class("Laplacian", comment=""" 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); }