diff --git a/CITATION.cff b/CITATION.cff index 345fd55d06..ab96c9484b 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -139,11 +139,11 @@ authors: - family-names: Wang given-names: Zhanhui -version: 4.1.2 -date-released: 2017-12-01 +version: 4.2.0 +date-released: TBC repository-code: https://github.com/boutproject/BOUT-dev url: http://boutproject.github.io/ -doi: 10.5281/zenodo.1423213 +doi: TBC license: 'LGPL-3.0-or-later' references: - type: article diff --git a/bin/bout-squashoutput b/bin/bout-squashoutput index cfc6154710..cd3ccf5f92 100755 --- a/bin/bout-squashoutput +++ b/bin/bout-squashoutput @@ -9,37 +9,42 @@ from sys import exit try: import argcomplete except ImportError: - argcomplete=None + argcomplete = None import boutdata.squashoutput as squash # Parse command line arguments -parser = argparse.ArgumentParser(squash.__doc__+"\n\n"+squash.squashoutput.__doc__) +parser = argparse.ArgumentParser( + squash.__doc__ + "\n\n" + squash.squashoutput.__doc__) + def str_to_bool(string): - return string.lower()=="true" or string.lower()=="t" + return string.lower() == "true" or string.lower() == "t" + def int_or_none(string): try: return int(string) except ValueError: - if string.lower()=='none' or string.lower()=='n': + if string.lower() == 'none' or string.lower() == 'n': return None else: raise parser.add_argument("datadir", nargs='?', default=".") -parser.add_argument("--outputname",default="BOUT.dmp.nc") +parser.add_argument("--outputname", default="BOUT.dmp.nc") parser.add_argument("--tind", type=int_or_none, nargs='*', default=[None]) parser.add_argument("--xind", type=int_or_none, nargs='*', default=[None]) parser.add_argument("--yind", type=int_or_none, nargs='*', default=[None]) parser.add_argument("--zind", type=int_or_none, nargs='*', default=[None]) -parser.add_argument("-s","--singleprecision", action="store_true", default=False) -parser.add_argument("-c","--compress", action="store_true", default=False) -parser.add_argument("-l","--complevel", type=int_or_none, default=None) -parser.add_argument("-i","--least-significant-digit", type=int_or_none, default=None) -parser.add_argument("-q","--quiet", action="store_true", default=False) -parser.add_argument("-a","--append", action="store_true", default=False) -parser.add_argument("-d","--delete", action="store_true", default=False) +parser.add_argument("-s", "--singleprecision", + action="store_true", default=False) +parser.add_argument("-c", "--compress", action="store_true", default=False) +parser.add_argument("-l", "--complevel", type=int_or_none, default=None) +parser.add_argument("-i", "--least-significant-digit", + type=int_or_none, default=None) +parser.add_argument("-q", "--quiet", action="store_true", default=False) +parser.add_argument("-a", "--append", action="store_true", default=False) +parser.add_argument("-d", "--delete", action="store_true", default=False) if argcomplete: argcomplete.autocomplete(parser) @@ -49,7 +54,7 @@ args = parser.parse_args() # Late imports to not slow down bash completion for ind in "txyz": - args.__dict__[ind+"ind"]=slice(*args.__dict__[ind+"ind"]) + args.__dict__[ind + "ind"] = slice(*args.__dict__[ind + "ind"]) # Call the function, using command line arguments squash.squashoutput(**args.__dict__) diff --git a/configure b/configure index 81ee0d7f7a..dba763cd86 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for BOUT++ 4.1.2. +# Generated by GNU Autoconf 2.69 for BOUT++ 4.2.0. # # Report bugs to . # @@ -580,8 +580,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='BOUT++' PACKAGE_TARNAME='bout--' -PACKAGE_VERSION='4.1.2' -PACKAGE_STRING='BOUT++ 4.1.2' +PACKAGE_VERSION='4.2.0' +PACKAGE_STRING='BOUT++ 4.2.0' PACKAGE_BUGREPORT='bd512@york.ac.uk' PACKAGE_URL='' @@ -1359,7 +1359,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures BOUT++ 4.1.2 to adapt to many kinds of systems. +\`configure' configures BOUT++ 4.2.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1421,7 +1421,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of BOUT++ 4.1.2:";; + short | recursive ) echo "Configuration of BOUT++ 4.2.0:";; esac cat <<\_ACEOF @@ -1550,7 +1550,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -BOUT++ configure 4.1.2 +BOUT++ configure 4.2.0 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2131,7 +2131,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by BOUT++ $as_me 4.1.2, which was +It was created by BOUT++ $as_me 4.2.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -12705,7 +12705,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by BOUT++ $as_me 4.1.2, which was +This file was extended by BOUT++ $as_me 4.2.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -12758,7 +12758,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -BOUT++ config.status 4.1.2 +BOUT++ config.status 4.2.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" @@ -13933,7 +13933,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by BOUT++ $as_me 4.1.2, which was +This file was extended by BOUT++ $as_me 4.2.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -13986,7 +13986,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -BOUT++ config.status 4.1.2 +BOUT++ config.status 4.2.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 7cd03e2948..21dd288bbc 100644 --- a/configure.ac +++ b/configure.ac @@ -32,7 +32,7 @@ # AC_PREREQ([2.69]) -AC_INIT([BOUT++],[4.1.2],[bd512@york.ac.uk]) +AC_INIT([BOUT++],[4.2.0],[bd512@york.ac.uk]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_MACRO_DIR([m4]) diff --git a/examples/bout_runners_example/diffusion_3D.cxx b/examples/bout_runners_example/diffusion_3D.cxx index cd96607715..670472eb99 100644 --- a/examples/bout_runners_example/diffusion_3D.cxx +++ b/examples/bout_runners_example/diffusion_3D.cxx @@ -60,8 +60,8 @@ int physics_init(bool restarting) { // The boundary lies (1/2)*dx away from the last point As there // are 2 boundaries there will effectively add one more line // segment in the domain. Hence - mesh->coordinates()->dx = Lx/(internal_x_points); - mesh->coordinates()->dy = Ly/(internal_y_points); + mesh->getCoordinates()->dx = Lx/(internal_x_points); + mesh->getCoordinates()->dy = Ly/(internal_y_points); } // ************************************************************************ diff --git a/examples/laplacexy/alfven-wave/alfven.cxx b/examples/laplacexy/alfven-wave/alfven.cxx index 92a0b267b6..8bac88f844 100644 --- a/examples/laplacexy/alfven-wave/alfven.cxx +++ b/examples/laplacexy/alfven-wave/alfven.cxx @@ -170,7 +170,7 @@ class Alfven : public PhysicsModel { Field2D Rxy, Bpxy, Btxy, hthe, sinty; GRID_LOAD5(Rxy, Bpxy, Btxy, hthe, sinty); // Load metrics - Coordinates *coord = mesh->coordinates(); // Metric tensor + Coordinates *coord = mesh->getCoordinates(); // Metric tensor // Checking for dpsi and qinty used in BOUT grids Field2D dx; diff --git a/examples/laplacexy/laplace_perp/test.cxx b/examples/laplacexy/laplace_perp/test.cxx index a4b561d027..0ed64932b6 100644 --- a/examples/laplacexy/laplace_perp/test.cxx +++ b/examples/laplacexy/laplace_perp/test.cxx @@ -20,7 +20,7 @@ int main(int argc, char** argv) { mesh->get(hthe, "hthe"); // m mesh->get(I, "sinty");// m^-2 T^-1 - Coordinates *coord = mesh->coordinates(); + Coordinates *coord = mesh->getCoordinates(); // Calculate metrics coord->g11 = SQ(Rxy * Bpxy); diff --git a/examples/orszag-tang/mhd.cxx b/examples/orszag-tang/mhd.cxx index 60870bac4a..eee6c16205 100644 --- a/examples/orszag-tang/mhd.cxx +++ b/examples/orszag-tang/mhd.cxx @@ -47,7 +47,7 @@ class MHD : public PhysicsModel { B.covariant = false; // evolve contravariant components bout_solve(B, "B"); - Coordinates *coord = mesh->coordinates(); + Coordinates *coord = mesh->getCoordinates(); output.write("dx[0,0] = %e, dy[0,0] = %e, dz = %e\n", coord->dx(0, 0), coord->dy(0, 0), coord->dz); diff --git a/examples/tokamak-2fluid/2fluid.cxx b/examples/tokamak-2fluid/2fluid.cxx index 7b95ddcca3..93f55fa3e2 100644 --- a/examples/tokamak-2fluid/2fluid.cxx +++ b/examples/tokamak-2fluid/2fluid.cxx @@ -101,7 +101,7 @@ class TwoFluid : public PhysicsModel { Field2D I; // Shear factor // Get the coordinate system - coord = mesh->coordinates(); + coord = mesh->getCoordinates(); output.write("Solving 6-variable 2-fluid equations\n"); diff --git a/include/bout/coordinates.hxx b/include/bout/coordinates.hxx index ba9522c6c3..e649cdfcc7 100644 --- a/include/bout/coordinates.hxx +++ b/include/bout/coordinates.hxx @@ -123,8 +123,8 @@ public: const Field3D Div_par(const Field3D &f, CELL_LOC outloc=CELL_DEFAULT, DIFF_METHOD method=DIFF_DEFAULT); // Second derivative along magnetic field - const Field2D Grad2_par2(const Field2D &f, CELL_LOC outloc=CELL_DEFAULT); - const Field3D Grad2_par2(const Field3D &f, CELL_LOC outloc=CELL_DEFAULT); + const Field2D Grad2_par2(const Field2D &f, CELL_LOC outloc=CELL_DEFAULT, DIFF_METHOD method=DIFF_DEFAULT); + const Field3D Grad2_par2(const Field3D &f, CELL_LOC outloc=CELL_DEFAULT, DIFF_METHOD method=DIFF_DEFAULT); // Perpendicular Laplacian operator, using only X-Z derivatives // NOTE: This might be better bundled with the Laplacian inversion code diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index f3682c9dbd..fcee0e58e3 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -430,20 +430,25 @@ class Mesh { bool IncIntShear; ///< Include integrated shear (if shifting X) /// Coordinate system - Coordinates *coordinates(const CELL_LOC location = CELL_CENTRE) { + Coordinates *getCoordinates(const CELL_LOC location = CELL_CENTRE) { + ASSERT1(location != CELL_DEFAULT); + ASSERT1(location != CELL_VSHIFT); + if (coords_map.count(location)) { // True branch most common, returns immediately return coords_map[location].get(); - } else if (location == CELL_DEFAULT) { - throw BoutException("Ambiguous location 'CELL_DEFAULT' passed to mesh::coordinates"); } else { // No coordinate system set. Create default // Note that this can't be allocated here due to incomplete type // (circular dependency between Mesh and Coordinates) - coords_map.insert(std::pair >(location, createDefaultCoordinates(location))); + coords_map.emplace(location, createDefaultCoordinates(location)); return coords_map[location].get(); } } + Coordinates *DEPRECATED(coordinates(const CELL_LOC location = CELL_CENTRE)) { + return getCoordinates(location); + } + // First derivatives in index space // Implemented in src/mesh/index_derivs.hxx @@ -650,12 +655,12 @@ class Mesh { /// Get the named region from the region_map for the data iterator /// /// Throws if region_name not found - Region<> &getRegion(const std::string ®ion_name){ + const Region<> &getRegion(const std::string ®ion_name) const{ return getRegion3D(region_name); } - Region &getRegion3D(const std::string ®ion_name); - Region &getRegion2D(const std::string ®ion_name); - Region &getRegionPerp(const std::string ®ion_name); + const Region &getRegion3D(const std::string ®ion_name) const; + const Region &getRegion2D(const std::string ®ion_name) const; + const Region &getRegionPerp(const std::string ®ion_name) const; /// Add a new region to the region_map for the data iterator /// diff --git a/include/bout/region.hxx b/include/bout/region.hxx index d11587ef98..d4671ebe25 100644 --- a/include/bout/region.hxx +++ b/include/bout/region.hxx @@ -483,8 +483,10 @@ public: /// Note that if the indices are altered using these iterators, the /// blocks may become out of sync and will need to manually updated typename RegionIndices::iterator begin() { return std::begin(indices); }; + typename RegionIndices::const_iterator begin() const { return std::begin(indices); }; typename RegionIndices::const_iterator cbegin() const { return indices.cbegin(); }; typename RegionIndices::iterator end() { return std::end(indices); }; + typename RegionIndices::const_iterator end() const { return std::end(indices); }; typename RegionIndices::const_iterator cend() const { return indices.cend(); }; const ContiguousBlocks &getBlocks() const { return blocks; }; diff --git a/include/difops.hxx b/include/difops.hxx index 029fade7eb..52caf84bc5 100644 --- a/include/difops.hxx +++ b/include/difops.hxx @@ -173,7 +173,7 @@ const Field3D Div_par(const Field3D &f, const Field3D &v); * * Note: For parallel Laplacian use LaplacePar */ -const Field2D Grad2_par2(const Field2D &f, CELL_LOC outloc=CELL_DEFAULT); +const Field2D Grad2_par2(const Field2D &f, CELL_LOC outloc=CELL_DEFAULT, DIFF_METHOD method=DIFF_DEFAULT); /*! * second parallel derivative @@ -186,7 +186,7 @@ const Field2D Grad2_par2(const Field2D &f, CELL_LOC outloc=CELL_DEFAULT); * @param[in] f The field to be differentiated * @param[in] outloc The cell location of the result */ -const Field3D Grad2_par2(const Field3D &f, CELL_LOC outloc=CELL_DEFAULT); +const Field3D Grad2_par2(const Field3D &f, CELL_LOC outloc=CELL_DEFAULT, DIFF_METHOD method=DIFF_DEFAULT); /*! * Parallel derivatives, converting between cell-centred and lower cell boundary diff --git a/include/field2d.hxx b/include/field2d.hxx index b261ca8456..51e14607ab 100644 --- a/include/field2d.hxx +++ b/include/field2d.hxx @@ -154,6 +154,10 @@ class Field2D : public Field, public FieldData { */ const IndexRange DEPRECATED(region(REGION rgn)) const override; + /// Return a Region reference to use to iterate over this field + const Region& getRegion(REGION region) const; + const Region& getRegion(const std::string ®ion_name) const; + BoutReal& operator[](const Ind2D &d) { return data[d.ind]; } diff --git a/include/field3d.hxx b/include/field3d.hxx index bd085f7c73..1025f935ab 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -328,6 +328,10 @@ class Field3D : public Field, public FieldData { */ const IndexRange DEPRECATED(region2D(REGION rgn)) const; + /// Return a Region reference to use to iterate over this field + const Region& getRegion(REGION region) const; + const Region& getRegion(const std::string ®ion_name) const; + /*! * Direct data access using DataIterator object. * This uses operator(x,y,z) so checks will only be diff --git a/include/field_data.hxx b/include/field_data.hxx index c4fadd4e95..5124726a92 100644 --- a/include/field_data.hxx +++ b/include/field_data.hxx @@ -62,12 +62,23 @@ class FieldVisitor; */ class FieldData { public: - FieldData(); + FieldData(Mesh *datamesh = nullptr) + : fielddatamesh(datamesh != nullptr ? datamesh : mesh), boundaryIsCopy(false), + boundaryIsSet(true) {} + virtual ~FieldData(); // Visitor pattern support virtual void accept(FieldVisitor &v) = 0; - + + Mesh *getDataMesh() const { + if (fielddatamesh != nullptr) { + return fielddatamesh; + } else { + return mesh; + } + } + // Defines interface which must be implemented virtual bool isReal() const = 0; ///< Returns true if field consists of BoutReal values virtual bool is3D() const = 0; ///< True if variable is 3D @@ -92,6 +103,7 @@ public: FieldGeneratorPtr getBndryGenerator(BndryLoc location); protected: + Mesh* fielddatamesh; vector bndry_op; ///< Boundary conditions bool boundaryIsCopy; ///< True if bndry_op is a copy bool boundaryIsSet; ///< Set to true when setBoundary called diff --git a/include/fieldperp.hxx b/include/fieldperp.hxx index 8fef875e8a..90fdcf03d8 100644 --- a/include/fieldperp.hxx +++ b/include/fieldperp.hxx @@ -91,6 +91,10 @@ class FieldPerp : public Field { const IndexRange DEPRECATED(region(REGION rgn)) const override; + /// Return a Region reference to use to iterate over this field + const Region& getRegion(REGION region) const; + const Region& getRegion(const std::string ®ion_name) const; + /*! * Direct data access using DataIterator indexing */ diff --git a/include/vecops.hxx b/include/vecops.hxx index 14b021ef67..ca06def8d2 100644 --- a/include/vecops.hxx +++ b/include/vecops.hxx @@ -1,6 +1,6 @@ /*!************************************************************************ * \file vecops.hxx - * + * * Operators on vector objects * B.Dudson, October 2007 * @@ -8,7 +8,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 @@ -36,6 +36,8 @@ /// Gradient of scalar field \p f, returning a covariant vector /// +/// All locations supported +/// /// @param[in] f The field to differentiate /// @param[in] outloc The location where the result is desired (if staggered meshes are enabled) /// By default this is the same location as the input \p f @@ -44,31 +46,50 @@ const Vector3D Grad(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT); /// Gradient of scalar field \p f, returning a covariant vector /// +/// All locations supported +/// /// @param[in] f The field to differentiate /// @param[in] outloc_x The cell location where the X component should be defined /// @param[in] outloc_y The cell location where the Y component should be defined /// @param[in] outloc_z The cell location where the Z component should be defined -const Vector3D Grad(const Field3D &f, - CELL_LOC outloc_x, CELL_LOC outloc_y, CELL_LOC outloc_z = CELL_DEFAULT); +const Vector3D DEPRECATED(Grad(const Field3D &f, CELL_LOC outloc_x, CELL_LOC outloc_y, + CELL_LOC outloc_z)); + +/// Perpendicular gradient of scalar field \p f +/// +/// outloc must be either CELL_DEFAULT or f.getLocation() --> argument can be removed +/// +/// result.x = df/dx - g_12/(JB)^2 df/dy +/// result.y = 0 +/// result.z = df/dz - g_23/(JB)^2 df/dy +/// +/// @param[in] f The field to differentiate +/// @param[in] outloc The cell location where the result is desired +/// +const Vector3D Grad_perp(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT); /// Perpendicular gradient of scalar field \p f /// +/// +/// outloc must all be the same and must be either CELL_DEFAULT or f.getLocation() --> arguments can be removed +/// /// result.x = df/dx - g_12/(JB)^2 df/dy /// result.y = 0 /// result.z = df/dz - g_23/(JB)^2 df/dy -/// +/// /// @param[in] f The field to differentiate /// @param[in] outloc_x The cell location where the X component should be defined /// @param[in] outloc_y The cell location where the Y component should be defined /// @param[in] outloc_z The cell location where the Z component should be defined /// -const Vector3D Grad_perp(const Field3D &f, - CELL_LOC outloc_x = CELL_DEFAULT, - CELL_LOC outloc_y = CELL_DEFAULT, - CELL_LOC outloc_z = CELL_DEFAULT); +const Vector3D DEPRECATED(Grad_perp(const Field3D &f, CELL_LOC outloc_x, + CELL_LOC outloc_y, CELL_LOC outloc_z)); /// Divergence of a vector \p v, returning a scalar /// +/// All locations except `CELL_VSHIFT` supported. Note that if \p v is +/// at `CELL_VSHIFT`, then \p outloc must be `CELL_CENTRE` +/// /// @param[in] v The vector to differentiate /// @param[in] outloc The cell location where the result is desired /// @@ -82,23 +103,44 @@ const Field3D Div(const Vector3D &v, const Field3D &f); /// Curl of a vector /// +/// Does not currently support any output locations. \p v must not be +/// at `CELL_VSHIFT` +/// +/// We can't support VSHIFT here as, e.g. DDY can't produce an output +/// at CELL_XLOW unless the input field is at CELL_XLOW, but then that +/// field will also be needed at CELL_YLOW, for example for another +/// component. +/// /// @param[in] v The vector to differentiate -/// @param[in] outloc The cell location where the result is desired /// -const Vector2D Curl(const Vector2D &v, CELL_LOC outloc = CELL_DEFAULT); -const Vector3D Curl(const Vector3D &v, CELL_LOC outloc = CELL_DEFAULT); -const Vector3D Curl(const Vector3D &v, - CELL_LOC outloc_x, CELL_LOC outloc_y, CELL_LOC outloc_z); +const Vector2D Curl(const Vector2D &v); +const Vector3D Curl(const Vector3D &v); +inline const Vector2D DEPRECATED(Curl(const Vector2D &v, CELL_LOC UNUSED(outloc))) { + return Curl(v); +} +inline const Vector3D DEPRECATED(Curl(const Vector3D &v, CELL_LOC UNUSED(outloc))) { + return Curl(v); +} +inline const Vector3D DEPRECATED(Curl(const Vector3D &v, CELL_LOC UNUSED(outloc_x), + CELL_LOC UNUSED(outloc_y), + CELL_LOC UNUSED(outloc_z))) { + return Curl(v); +} // Upwinding routines /// Advection of a scalar field \p f by a velocity vector \p v +/// +/// The vector and the field must be at the same location, which +/// cannot be CELL_VSHIFT const Field2D V_dot_Grad(const Vector2D &v, const Field2D &f); const Field3D V_dot_Grad(const Vector2D &v, const Field3D &f); const Field3D V_dot_Grad(const Vector3D &v, const Field2D &f); const Field3D V_dot_Grad(const Vector3D &v, const Field3D &f); /// Advection of a vector field \p a by a velocity vector \p v +/// +/// Both vectors must be at the same location, which cannot be CELL_VSHIFT const Vector2D V_dot_Grad(const Vector2D &v, const Vector2D &a); const Vector3D V_dot_Grad(const Vector2D &v, const Vector3D &a); const Vector3D V_dot_Grad(const Vector3D &v, const Vector2D &a); diff --git a/manual/doxygen/Doxyfile b/manual/doxygen/Doxyfile index d7067d0171..3271607d7a 100644 --- a/manual/doxygen/Doxyfile +++ b/manual/doxygen/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = BOUT++ # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 4.1.2 +PROJECT_NUMBER = 4.2.0 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/manual/doxygen/Doxyfile_readthedocs b/manual/doxygen/Doxyfile_readthedocs index 4249ec2ebd..7f3dfd8a94 100644 --- a/manual/doxygen/Doxyfile_readthedocs +++ b/manual/doxygen/Doxyfile_readthedocs @@ -38,7 +38,7 @@ PROJECT_NAME = BOUT++ # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 4.1.2 +PROJECT_NUMBER = 4.2.0 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/manual/sphinx/conf.py b/manual/sphinx/conf.py index 5e514e3283..9c39c2ac27 100755 --- a/manual/sphinx/conf.py +++ b/manual/sphinx/conf.py @@ -131,9 +131,9 @@ def __getattr__(cls, name): # built documents. # # The short X.Y version. -version = '4.1' +version = '4.2' # The full version, including alpha/beta/rc tags. -release = '4.1.2' +release = '4.2.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/manual/sphinx/developer_docs/data_types.rst b/manual/sphinx/developer_docs/data_types.rst index aec326d7f3..6bfffff328 100644 --- a/manual/sphinx/developer_docs/data_types.rst +++ b/manual/sphinx/developer_docs/data_types.rst @@ -265,7 +265,7 @@ to OpenMP parallelise or vectorise:: } If you wish to vectorise but can't use OpenMP then there is a serial -verion of the macro: +verion of the macro:: BoutReal max=0.; BOUT_FOR_SERIAL(i, region) { @@ -285,10 +285,10 @@ For loops inside parallel regions, there is ``BOUT_FOR_INNER``:: If a more general OpenMP directive is needed, there is ``BOUT_FOR_OMP``:: - BoutReal result=0.; - BOUT_FOR_OMP(i, region, parallel for reduction(max:result)) { - result = f[i] > result ? f[i] : result; - } + BoutReal result=0.; + BOUT_FOR_OMP(i, region, parallel for reduction(max:result)) { + result = f[i] > result ? f[i] : result; + } The iterator provides access to the x, y, z indices:: @@ -304,11 +304,11 @@ modulo operators are needed to calculate individual indices. To perform finite difference or similar operators, index offsets can be calculated:: - Field3D f = ...; - Field3D g(0.0); - BOUT_FOR(i, f.getMesh()->getRegion3D("RGN_NOBNDRY")) { - g[i] = f[i.xp()] - f[i.xm()]; - } + Field3D f = ...; + Field3D g(0.0); + BOUT_FOR(i, f.getMesh()->getRegion3D("RGN_NOBNDRY")) { + g[i] = f[i.xp()] - f[i.xm()]; + } The ``xp()`` function by default produces an offset of ``+1`` in ``X``, ``xm()`` an offset of ``-1`` in the ``X`` direction. These functions can also diff --git a/manual/sphinx/user_docs/advanced_install.rst b/manual/sphinx/user_docs/advanced_install.rst index ee6e80ecde..6468f31d47 100644 --- a/manual/sphinx/user_docs/advanced_install.rst +++ b/manual/sphinx/user_docs/advanced_install.rst @@ -53,7 +53,7 @@ control over how BOUT++ is built: - ``SUNDIALS_EXTRA_LIBS`` specifies additional libraries for linking to SUNDIALS, which are put at the end of the link command. - + It is possible to change flags for BOUT++ after running configure, by editing the ``make.config`` file. Note that this is not recommended, as e.g. PVODE will not be built with these flags. @@ -165,13 +165,14 @@ To compile for the SKL partition, configure with to enable AVX512 vectorization. -.. note:: As of 20/04/2018, an issue with the netcdf and netcdf-cxx4 modules - means that you will need to remove ``-lnetcdf`` from ``EXTRA_LIBS`` in - ``make.config`` after running ``./configure`` and before running - ``make``. ``-lnetcdf`` needs also to be removed from ``bin/bout-config`` - to allow a successful build of the python interface. Recreation of - ``boutcore.pyx`` needs to be manually triggered, if - ``boutcore.pyx`` has already been created. +.. note:: As of 20/04/2018, an issue with the netcdf and netcdf-cxx4 + modules means that you will need to remove ``-lnetcdf`` from + ``EXTRA_LIBS`` in ``make.config`` after running + ``./configure`` and before running ``make``. ``-lnetcdf`` + needs also to be removed from ``bin/bout-config`` to allow a + successful build of the python interface. Recreation of + ``boutcore.pyx`` needs to be manually triggered, if + ``boutcore.pyx`` has already been created. Ubgl ~~~~ @@ -258,12 +259,38 @@ appropriately. OpenMP ------ -BOUT++ can make use of Single-Instruction Multiple-Data (SIMD) -parallelism through OpenMP. To enable OpenMP, use the +BOUT++ can make use of OpenMP parallelism. To enable OpenMP, use the ``--enable-openmp`` flag to configure:: ./configure --enable-openmp +OpenMP can be used to parallelise in more directions than can be +achieved with MPI alone. For example, it is currently difficult to +parallelise in X using pure MPI if FCI is used, and impossible to +parallelise at all in Z with pure MPI. + +OpenMP is in a large number of places now, such that a decent speed-up +can be achieved with OpenMP alone. Hybrid parallelisation with both +MPI and OpenMP can lead to more significant speed-ups, but it +sometimes requires some fine tuning of numerical parameters in order +to achieve this. This greatly depends on the details not just of your +system, but also your particular problem. We have tried to choose +"sensible" defaults that will work well for the most common cases, but +this is not always possible. You may need to perform some testing +yourself to find e.g. the optimum split of OpenMP threads and MPI +ranks. + +One such parameter that can potentially have a significant effect (for +some problem sizes on some machines) is setting the OpenMP schedule +used in some of the OpenMP loops (specifically those using +`BOUT_FOR`). This can be set using:: + + ./configure --enable-openmp --with-openmp-schedule= + +with ```` being one of: ``static`` (the default), +``dynamic``, ``guided``, ``auto`` or ``runtime``. + + .. note:: If you want to use OpenMP with Clang, you will need Clang 3.7+, and either ``libomp`` or ``libiomp``. @@ -277,6 +304,14 @@ parallelism through OpenMP. To enable OpenMP, use the By default PVODE is built without OpenMP support. To enable this add ``--enable-pvode-openmp`` to the configure command. + +.. note:: + OpenMP will attempt to use all available threads by default. This + can cause oversubscription problems on certain systems. You can + limit the number of threads OpenMP uses with the + ``OMP_NUM_THREADS`` environment variable. See your system + documentation for more details. + .. _sec-sundials: SUNDIALS diff --git a/src/field/field.cxx b/src/field/field.cxx index e3aa850248..365294d8df 100644 --- a/src/field/field.cxx +++ b/src/field/field.cxx @@ -60,14 +60,14 @@ Coordinates *Field::getCoordinates() const { if (fieldCoordinates) { return fieldCoordinates; } else { - fieldCoordinates = getMesh()->coordinates(getLocation()); + fieldCoordinates = getMesh()->getCoordinates(getLocation()); return fieldCoordinates; } } Coordinates *Field::getCoordinates(CELL_LOC loc) const { if (loc == CELL_DEFAULT) return getCoordinates(); - return getMesh()->coordinates(loc); + return getMesh()->getCoordinates(loc); } int Field::getNx() const{ diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index c7859f1d46..6af68cf44d 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -45,7 +45,8 @@ #include -Field2D::Field2D(Mesh *localmesh) : Field(localmesh), deriv(nullptr) { +Field2D::Field2D(Mesh *localmesh) : + Field(localmesh), FieldData(localmesh), deriv(nullptr) { boundaryIsSet = false; @@ -66,10 +67,13 @@ Field2D::Field2D(Mesh *localmesh) : Field(localmesh), deriv(nullptr) { } Field2D::Field2D(const Field2D& f) : Field(f.fieldmesh), // The mesh containing array sizes + FieldData(f.fielddatamesh), data(f.data), // This handles references to the data array deriv(nullptr) { TRACE("Field2D(Field2D&)"); + ASSERT1(fieldmesh == fielddatamesh); // Check consistency between Field::fieldmesh and FieldData::fielddatamesh + #ifdef TRACK name = f.name; #endif @@ -95,7 +99,9 @@ Field2D::Field2D(const Field2D& f) : Field(f.fieldmesh), // The mesh containing boundaryIsSet = false; } -Field2D::Field2D(BoutReal val, Mesh *localmesh) : Field(localmesh), deriv(nullptr) { +Field2D::Field2D(BoutReal val, Mesh *localmesh) : + Field(localmesh), FieldData(localmesh), deriv(nullptr) { + boundaryIsSet = false; nx = fieldmesh->LocalNx; @@ -179,6 +185,13 @@ const IndexRange Field2D::region(REGION rgn) const { }; } +const Region &Field2D::getRegion(REGION region) const { + return fieldmesh->getRegion2D(REGION_STRING(region)); +}; +const Region &Field2D::getRegion(const std::string ®ion_name) const { + return fieldmesh->getRegion2D(region_name); +}; + void Field2D::setLocation(CELL_LOC new_location) { if (getMesh()->StaggerGrids) { if (new_location == CELL_VSHIFT) { @@ -237,7 +250,9 @@ Field2D &Field2D::operator=(const Field2D &rhs) { #endif // Copy the data and data sizes - fieldmesh = rhs.fieldmesh; + fieldmesh = rhs.getMesh(); + fielddatamesh = rhs.getDataMesh(); + ASSERT1(fieldmesh == fielddatamesh); // Check consistency between Field::fieldmesh and FieldData::fielddatamesh nx = rhs.nx; ny = rhs.ny; diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index c62900285a..34acc5e47d 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -45,8 +45,8 @@ /// Constructor Field3D::Field3D(Mesh *localmesh) - : Field(localmesh), background(nullptr), deriv(nullptr), yup_field(nullptr), - ydown_field(nullptr) { + : Field(localmesh), FieldData(localmesh), background(nullptr), + deriv(nullptr), yup_field(nullptr), ydown_field(nullptr) { #ifdef TRACK name = ""; #endif @@ -71,11 +71,14 @@ Field3D::Field3D(Mesh *localmesh) /// later) Field3D::Field3D(const Field3D &f) : Field(f.fieldmesh), // The mesh containing array sizes + FieldData(f.fielddatamesh), background(nullptr), data(f.data), // This handles references to the data array deriv(nullptr), yup_field(nullptr), ydown_field(nullptr) { TRACE("Field3D(Field3D&)"); + ASSERT1(fieldmesh == fielddatamesh); // Check consistency between Field::fieldmesh and FieldData::fielddatamesh + #if CHECK > 2 checkData(f); #endif @@ -100,11 +103,13 @@ Field3D::Field3D(const Field3D &f) } Field3D::Field3D(const Field2D &f) - : Field(f.getMesh()), background(nullptr), deriv(nullptr), yup_field(nullptr), - ydown_field(nullptr) { + : Field(f.getMesh()), FieldData(f.getDataMesh()), background(nullptr), + deriv(nullptr), yup_field(nullptr), ydown_field(nullptr) { TRACE("Field3D: Copy constructor from Field2D"); + ASSERT1(fieldmesh == fielddatamesh); // Check consistency between Field::fieldmesh and FieldData::fielddatamesh + boundaryIsSet = false; nx = fieldmesh->LocalNx; @@ -118,8 +123,8 @@ Field3D::Field3D(const Field2D &f) } Field3D::Field3D(const BoutReal val, Mesh *localmesh) - : Field(localmesh), background(nullptr), deriv(nullptr), yup_field(nullptr), - ydown_field(nullptr) { + : Field(localmesh), FieldData(localmesh), background(nullptr), + deriv(nullptr), yup_field(nullptr), ydown_field(nullptr) { TRACE("Field3D: Copy constructor from value"); @@ -355,6 +360,13 @@ const IndexRange Field3D::region2D(REGION rgn) const { }; } +const Region &Field3D::getRegion(REGION region) const { + return fieldmesh->getRegion3D(REGION_STRING(region)); +}; +const Region &Field3D::getRegion(const std::string ®ion_name) const { + return fieldmesh->getRegion3D(region_name); +}; + /////////////////// ASSIGNMENT //////////////////// Field3D & Field3D::operator=(const Field3D &rhs) { @@ -368,7 +380,9 @@ Field3D & Field3D::operator=(const Field3D &rhs) { checkData(rhs); // Copy the data and data sizes - fieldmesh = rhs.fieldmesh; + fieldmesh = rhs.getMesh(); + fielddatamesh = rhs.getDataMesh(); + ASSERT1(fieldmesh == fielddatamesh); // Check consistency between Field::fieldmesh and FieldData::fielddatamesh nx = rhs.nx; ny = rhs.ny; nz = rhs.nz; data = rhs.data; @@ -380,10 +394,14 @@ Field3D & Field3D::operator=(const Field3D &rhs) { Field3D & Field3D::operator=(const Field2D &rhs) { TRACE("Field3D = Field2D"); + + ASSERT1(fieldmesh == rhs.getMesh()); + ASSERT1(fielddatamesh == rhs.getDataMesh()); + ASSERT1(fieldmesh == fielddatamesh); // Check consistency between Field::fieldmesh and FieldData::fielddatamesh /// Check that the data is valid checkData(rhs); - + /// Make sure there's a unique array to copy data into allocate(); diff --git a/src/field/field_data.cxx b/src/field/field_data.cxx index 6ab19709c7..98bf71eaec 100644 --- a/src/field/field_data.cxx +++ b/src/field/field_data.cxx @@ -6,10 +6,6 @@ #include #include "unused.hxx" -FieldData::FieldData() : boundaryIsCopy(false), boundaryIsSet(true) { - -} - FieldData::~FieldData() { if(!boundaryIsCopy) { // Delete the boundary operations @@ -24,7 +20,7 @@ void FieldData::setBoundary(const string &name) { output_info << "Setting boundary for variable " << name << endl; /// Loop over the mesh boundary regions - for(const auto& reg : mesh->getBoundaries()) { + for(const auto& reg : getDataMesh()->getBoundaries()) { BoundaryOp* op = static_cast(bfact->createFromOptions(name, reg)); if (op != nullptr) bndry_op.push_back(op); @@ -32,9 +28,9 @@ void FieldData::setBoundary(const string &name) { } /// Get the mesh boundary regions - vector par_reg = mesh->getBoundariesPar(); + vector par_reg = getDataMesh()->getBoundariesPar(); /// Loop over the mesh parallel boundary regions - for(const auto& reg : mesh->getBoundariesPar()) { + for(const auto& reg : getDataMesh()->getBoundariesPar()) { BoundaryOpPar* op = static_cast(bfact->createFromOptions(name, reg)); if (op != nullptr) bndry_op_par.push_back(op); @@ -47,7 +43,7 @@ void FieldData::setBoundary(const string &name) { void FieldData::setBoundary(const string &UNUSED(region), BoundaryOp *op) { /// Get the mesh boundary regions - vector reg = mesh->getBoundaries(); + vector reg = getDataMesh()->getBoundaries(); /// Find the region @@ -76,7 +72,7 @@ void FieldData::addBndryFunction(FuncPtr userfunc, BndryLoc location){ void FieldData::addBndryGenerator(FieldGeneratorPtr gen, BndryLoc location) { if(location == BNDRY_ALL){ - for(const auto& reg : mesh->getBoundaries()) { + for(const auto& reg : getDataMesh()->getBoundaries()) { bndry_generator[reg->location] = gen; } } else { diff --git a/src/field/fieldgenerators.cxx b/src/field/fieldgenerators.cxx index 2eaeacbc2a..f2d7ecf430 100644 --- a/src/field/fieldgenerators.cxx +++ b/src/field/fieldgenerators.cxx @@ -160,7 +160,7 @@ BoutReal FieldBallooning::generate(double x, double y, double z, double t) { throw BoutException("ballooning function ball_n less than 1"); BoutReal ts; // Twist-shift angle - Coordinates* coords = mesh->coordinates(); + Coordinates* coords = mesh->getCoordinates(); // Need to find the nearest flux surface (x index) // This assumes that mesh->GlobalX is linear in x index diff --git a/src/field/fieldperp.cxx b/src/field/fieldperp.cxx index 856b6c0272..5bd7765e91 100644 --- a/src/field/fieldperp.cxx +++ b/src/field/fieldperp.cxx @@ -215,6 +215,13 @@ const IndexRange FieldPerp::region(REGION rgn) const { }; } +const Region &FieldPerp::getRegion(REGION region) const { + return fieldmesh->getRegionPerp(REGION_STRING(region)); +}; +const Region &FieldPerp::getRegion(const std::string ®ion_name) const { + return fieldmesh->getRegionPerp(region_name); +}; + //////////////// NON-MEMBER FUNCTIONS ////////////////// ////////////// NON-MEMBER OVERLOADED OPERATORS ////////////// diff --git a/src/field/vecops.cxx b/src/field/vecops.cxx index 6699ba03ad..3f2644e961 100644 --- a/src/field/vecops.cxx +++ b/src/field/vecops.cxx @@ -34,69 +34,103 @@ * Gradient operators **************************************************************************/ -const Vector2D Grad(const Field2D &f, CELL_LOC UNUSED(outloc)) { +const Vector2D Grad(const Field2D &f, CELL_LOC outloc) { + TRACE("Grad( Field2D )"); + + CELL_LOC outloc_x, outloc_y, outloc_z; + if (outloc == CELL_VSHIFT) { + outloc_x = CELL_XLOW; + outloc_y = CELL_YLOW; + outloc_z = CELL_ZLOW; + } else { + outloc_x = outloc_y = outloc_z = outloc; + } + Vector2D result(f.getMesh()); - TRACE("Grad( Field2D )"); - - result.x = DDX(f); - result.y = DDY(f); - result.z = DDZ(f); + result.x = DDX(f, outloc_x); + result.y = DDY(f, outloc_y); + result.z = DDZ(f, outloc_z); + + if (outloc == CELL_DEFAULT) { + result.setLocation(result.x.getLocation()); + } else { + result.setLocation(outloc); + } result.covariant = true; return result; } -const Vector3D Grad(const Field3D &f, - CELL_LOC outloc_x, CELL_LOC outloc_y, CELL_LOC outloc_z) { - Vector3D result(f.getMesh()); +const Vector3D Grad(const Field3D &f, CELL_LOC outloc_x, CELL_LOC outloc_y, + CELL_LOC outloc_z) { + // Note no Vector2D equivalent to this three location overload + TRACE("Grad( Field3D )"); + + ASSERT1((outloc_x == outloc_y && outloc_x == outloc_z) || + (outloc_x == CELL_XLOW && outloc_y == CELL_YLOW && + outloc_z == CELL_ZLOW)); // CELL_VSHIFT + CELL_LOC outloc = + (outloc_x == outloc_y && outloc_x == outloc_z) ? outloc_x : CELL_VSHIFT; + return Grad(f, outloc); +} + +const Vector3D Grad(const Field3D &f, CELL_LOC outloc) { TRACE("Grad( Field3D )"); - if(outloc_x == CELL_DEFAULT) - outloc_x = f.getLocation(); - if(outloc_y == CELL_DEFAULT) - outloc_y = f.getLocation(); - if(outloc_z == CELL_DEFAULT) - outloc_z = f.getLocation(); + CELL_LOC outloc_x, outloc_y, outloc_z; + if (outloc == CELL_VSHIFT) { + outloc_x = CELL_XLOW; + outloc_y = CELL_YLOW; + outloc_z = CELL_ZLOW; + } else { + outloc_x = outloc_y = outloc_z = outloc; + } + + Vector3D result(f.getMesh()); result.x = DDX(f, outloc_x); result.y = DDY(f, outloc_y); result.z = DDZ(f, outloc_z); + if (outloc == CELL_DEFAULT) { + result.setLocation(result.x.getLocation()); + } else { + result.setLocation(outloc); + } + result.covariant = true; - + return result; } -const Vector3D Grad(const Field3D &f, CELL_LOC outloc) { - if(outloc == CELL_VSHIFT) - return Grad(f, CELL_XLOW, CELL_YLOW, CELL_ZLOW); - - return Grad(f, outloc, outloc, outloc); +const Vector3D Grad_perp(const Field3D &f, CELL_LOC outloc_x, CELL_LOC outloc_y, + CELL_LOC outloc_z) { + TRACE("Grad_perp( Field3D )"); + ASSERT1(outloc_x == outloc_y && outloc_x == outloc_z); + ASSERT1(outloc_x == CELL_DEFAULT || outloc_x == f.getLocation()); + return Grad_perp(f, outloc_x); } -const Vector3D Grad_perp(const Field3D &f, CELL_LOC outloc_x, - CELL_LOC UNUSED(outloc_y), CELL_LOC outloc_z) { - Vector3D result(f.getMesh()); - +const Vector3D Grad_perp(const Field3D &f, CELL_LOC outloc) { TRACE("Grad_perp( Field3D )"); - if(outloc_x == CELL_DEFAULT) - outloc_x = f.getLocation(); - if(outloc_z == CELL_DEFAULT) - outloc_z = f.getLocation(); + ASSERT1(outloc == CELL_DEFAULT || outloc == f.getLocation()); - Coordinates* metric_x = mesh->coordinates(outloc_x); - Coordinates* metric_z = mesh->coordinates(outloc_z); + Coordinates *metric = f.getCoordinates(outloc); - result.x = DDX(f, outloc_x) - metric_x->g_12*DDY(f, outloc_x) / SQ(metric_x->J * metric_x->Bxy); + Vector3D result(f.getMesh()); + + result.x = DDX(f, outloc) - metric->g_12 * DDY(f, outloc) / SQ(metric->J * metric->Bxy); result.y = 0.0; - result.z = DDZ(f, outloc_z) - metric_z->g_23*DDY(f, outloc_z) / SQ(metric_z->J * metric_z->Bxy); + result.z = DDZ(f, outloc) - metric->g_23 * DDY(f, outloc) / SQ(metric->J * metric->Bxy); + + result.setLocation(result.x.getLocation()); result.covariant = true; - + return result; } @@ -107,10 +141,16 @@ const Vector3D Grad_perp(const Field3D &f, CELL_LOC outloc_x, const Field2D Div(const Vector2D &v, CELL_LOC outloc) { TRACE("Div( Vector2D )"); + if (outloc == CELL_DEFAULT) { + outloc = v.getLocation(); + } + + ASSERT1(outloc != CELL_VSHIFT); + Mesh *localmesh = v.x.getMesh(); Field2D result(localmesh); - Coordinates *metric = localmesh->coordinates(outloc); + Coordinates *metric = localmesh->getCoordinates(outloc); // get contravariant components of v Vector2D vcn = v; @@ -120,28 +160,32 @@ const Field2D Div(const Vector2D &v, CELL_LOC outloc) { result += DDY(metric->J*vcn.y, outloc); result += DDZ(metric->J*vcn.z, outloc); result /= metric->J; - + return result; } const Field3D Div(const Vector3D &v, CELL_LOC outloc) { TRACE("Div( Vector3D )"); + if (outloc == CELL_DEFAULT) { + outloc = v.getLocation(); + } + + // This also catches the combination of v at VSHIFT and outloc at DEFAULT + ASSERT1(outloc != CELL_VSHIFT); + Mesh *localmesh = v.x.getMesh(); Field3D result(localmesh); - Coordinates *metric = localmesh->coordinates(outloc); - - if(outloc == CELL_DEFAULT) - outloc = CELL_CENTRE; + Coordinates *metric = localmesh->getCoordinates(outloc); // get contravariant components of v Vector3D vcn = v; vcn.toContravariant(); - - result = DDX(metric->J*vcn.x, outloc); - result += DDY(metric->J*vcn.y, outloc); - result += DDZ(metric->J*vcn.z, outloc); + + result = DDX(vcn.x.getCoordinates()->J * vcn.x, outloc); + result += DDY(vcn.y.getCoordinates()->J * vcn.y, outloc); + result += DDZ(vcn.z.getCoordinates()->J * vcn.z, outloc); result /= metric->J; return result; @@ -154,53 +198,62 @@ const Field3D Div(const Vector3D &v, CELL_LOC outloc) { const Field2D Div(const Vector2D &v, const Field2D &f, CELL_LOC outloc) { TRACE("Div( Vector2D, Field2D )"); - ASSERT1(v.getLocation() == f.getLocation()); + if (outloc == CELL_DEFAULT) { + outloc = v.getLocation(); + } + + ASSERT1(outloc != CELL_VSHIFT); Mesh *localmesh = f.getMesh(); - Coordinates *metric = localmesh->coordinates(outloc); + Coordinates *metric = localmesh->getCoordinates(outloc); // get contravariant components of v Vector2D vcn = v; vcn.toContravariant(); Field2D result(localmesh); - result = FDDX(metric->J*vcn.x, f, outloc); - result += FDDY(metric->J*vcn.y, f, outloc); - result += FDDZ(metric->J*vcn.z, f, outloc); + result = FDDX(vcn.x.getCoordinates()->J * vcn.x, f, outloc); + result += FDDY(vcn.y.getCoordinates()->J * vcn.y, f, outloc); + result += FDDZ(vcn.z.getCoordinates()->J * vcn.z, f, outloc); result /= metric->J; - + return result; } -const Field3D Div(const Vector3D &v, const Field3D &f, DIFF_METHOD method, CELL_LOC outloc) { +const Field3D Div(const Vector3D &v, const Field3D &f, DIFF_METHOD method, + CELL_LOC outloc) { TRACE("Div( Vector3D, Field3D )"); - Mesh *localmesh = f.getMesh(); - Field3D result(localmesh); + if (outloc == CELL_DEFAULT) { + outloc = v.getLocation(); + } + ASSERT1(outloc != CELL_VSHIFT); - Coordinates *metric = localmesh->coordinates(outloc); + Mesh *localmesh = f.getMesh(); - if(outloc == CELL_DEFAULT) - outloc = CELL_CENTRE; + Coordinates *metric = localmesh->getCoordinates(outloc); // get contravariant components of v Vector3D vcn = v; vcn.toContravariant(); - - result = FDDX(metric->J*vcn.x, f, outloc, method); - result += FDDY(metric->J*vcn.y, f, outloc, method); - result += FDDZ(metric->J*vcn.z, f, outloc, method); + + Field3D result(localmesh); + result = FDDX(vcn.x.getCoordinates()->J * vcn.x, f, outloc, method); + result += FDDY(vcn.y.getCoordinates()->J * vcn.y, f, outloc, method); + result += FDDZ(vcn.z.getCoordinates()->J * vcn.z, f, outloc, method); result /= metric->J; - + return result; } const Field3D Div(const Vector3D &v, const Field3D &f, CELL_LOC outloc, DIFF_METHOD method) { + TRACE("Div( Vector3D, Field3D)"); return Div(v, f, method, outloc); } const Field3D Div(const Vector3D &v, const Field3D &f) { + TRACE("Div( Vector3D, Field3D)"); return Div(v, f, DIFF_DEFAULT, CELL_DEFAULT); } @@ -208,12 +261,13 @@ const Field3D Div(const Vector3D &v, const Field3D &f) { * Curl operators **************************************************************************/ -const Vector2D Curl(const Vector2D &v, CELL_LOC outloc) { +const Vector2D Curl(const Vector2D &v) { TRACE("Curl( Vector2D )"); + ASSERT1(v.getLocation() != CELL_VSHIFT); Mesh *localmesh = v.x.getMesh(); - Coordinates *metric = localmesh->coordinates(outloc); + auto metric = v.x.getCoordinates(); // Get covariant components of v Vector2D vco = v; @@ -221,26 +275,27 @@ const Vector2D Curl(const Vector2D &v, CELL_LOC outloc) { // get components (curl(v))^j Vector2D result(localmesh); - result.x = (DDY(vco.z, outloc) - DDZ(vco.y, outloc))/metric->J; - result.y = (DDZ(vco.x, outloc) - DDX(vco.z, outloc))/metric->J; - result.z = (DDX(vco.y, outloc) - DDY(vco.x, outloc))/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()); result.covariant = false; // result is contravariant return result; } -const Vector3D Curl(const Vector3D &v, - CELL_LOC outloc_x, CELL_LOC outloc_y, CELL_LOC outloc_z) { - +const Vector3D Curl(const Vector3D &v) { TRACE("Curl( Vector3D )"); - Mesh *localmesh = v.x.getMesh(); + ASSERT1(v.getLocation() != CELL_VSHIFT); - Coordinates* metric_z = localmesh->coordinates(outloc_z); + Mesh *localmesh = v.x.getMesh(); + auto metric = v.x.getCoordinates(); // Get covariant components of v Vector3D vco = v; @@ -248,34 +303,29 @@ const Vector3D Curl(const Vector3D &v, // get components (curl(v))^j Vector3D result(localmesh); - result.x = (DDY(vco.z, outloc_x) - DDZ(vco.y, outloc_x))/localmesh->coordinates(outloc_x)->J; - result.y = (DDZ(vco.x, outloc_y) - DDX(vco.z, outloc_y))/localmesh->coordinates(outloc_y)->J; - result.z = (DDX(vco.y, outloc_z) - DDY(vco.x, outloc_z))/metric_z->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_z->ShiftTorsion*vco.z / metric_z->J; + result.z -= metric->ShiftTorsion * vco.z / metric->J; + + result.setLocation(v.getLocation()); result.covariant = false; // result is contravariant return result; } -const Vector3D Curl(const Vector3D &v, CELL_LOC outloc) { - if(outloc == CELL_VSHIFT) - return Curl(v, CELL_XLOW, CELL_YLOW, CELL_ZLOW); - - return Curl(v, outloc, outloc, outloc); -} - /************************************************************************** * Upwinding operators **************************************************************************/ const Field2D V_dot_Grad(const Vector2D &v, const Field2D &f) { - Field2D result(f.getMesh()); - TRACE("V_dot_Grad( Vector2D , Field2D )"); + Field2D result(f.getMesh()); + // Get contravariant components of v Vector2D vcn = v; vcn.toContravariant(); @@ -286,10 +336,10 @@ const Field2D V_dot_Grad(const Vector2D &v, const Field2D &f) { } const Field3D V_dot_Grad(const Vector2D &v, const Field3D &f) { - Field3D result(f.getMesh()); - TRACE("V_dot_Grad( Vector2D , Field3D )"); + Field3D result(f.getMesh()); + // Get contravariant components of v Vector2D vcn = v; vcn.toContravariant(); @@ -300,10 +350,10 @@ const Field3D V_dot_Grad(const Vector2D &v, const Field3D &f) { } const Field3D V_dot_Grad(const Vector3D &v, const Field2D &f) { - Field3D result(f.getMesh()); - TRACE("V_dot_Grad( Vector3D , Field2D )"); + Field3D result(f.getMesh()); + // Get contravariant components of v Vector3D vcn = v; vcn.toContravariant(); @@ -314,10 +364,10 @@ const Field3D V_dot_Grad(const Vector3D &v, const Field2D &f) { } const Field3D V_dot_Grad(const Vector3D &v, const Field3D &f) { - Field3D result(f.getMesh()); - TRACE("V_dot_Grad( Vector3D , Field3D )"); + Field3D result(f.getMesh()); + // Get contravariant components of v Vector3D vcn = v; vcn.toContravariant(); @@ -327,206 +377,220 @@ const Field3D V_dot_Grad(const Vector3D &v, const Field3D &f) { return result; } -const Vector2D V_dot_Grad(const Vector2D &v, const Vector2D &a, const CELL_LOC outloc) { +const Vector2D V_dot_Grad(const Vector2D &v, const Vector2D &a) { TRACE("V_dot_Grad( Vector2D , Vector2D )"); - Mesh *localmesh = v.x.getMesh(); - Vector2D result(localmesh); + ASSERT1(v.getLocation() == a.getLocation()); + ASSERT1(v.getLocation() != CELL_VSHIFT); - Coordinates *metric = localmesh->coordinates(outloc); + Vector2D result{v.x.getMesh()}; + + auto metric = v.x.getCoordinates(); Vector2D vcn = v; vcn.toContravariant(); - if(a.covariant) { - - result.x = VDDX(vcn.x, a.x, outloc) + VDDY(vcn.y, a.x, outloc) + VDDZ(vcn.z, a.x, outloc); - result.x -= vcn.x*(metric->G1_11*a.x + metric->G2_11*a.y + metric->G3_11*a.z); - result.x -= vcn.y*(metric->G1_12*a.x + metric->G2_12*a.y + metric->G3_12*a.z); - result.x -= vcn.z*(metric->G1_13*a.x + metric->G2_13*a.y + metric->G3_13*a.z); + if (a.covariant) { + + result.x = VDDX(vcn.x, a.x) + VDDY(vcn.y, a.x) + VDDZ(vcn.z, a.x); + result.x -= vcn.x * (metric->G1_11 * a.x + metric->G2_11 * a.y + metric->G3_11 * a.z); + result.x -= vcn.y * (metric->G1_12 * a.x + metric->G2_12 * a.y + metric->G3_12 * a.z); + result.x -= vcn.z * (metric->G1_13 * a.x + metric->G2_13 * a.y + metric->G3_13 * a.z); - result.y = VDDX(vcn.x, a.y, outloc) + VDDY(vcn.y, a.y, outloc) + VDDZ(vcn.z, a.y, outloc); - result.y -= vcn.x*(metric->G1_12*a.x + metric->G2_12*a.y + metric->G3_12*a.z); - result.y -= vcn.y*(metric->G1_22*a.x + metric->G2_22*a.y + metric->G3_22*a.z); - result.y -= vcn.z*(metric->G1_23*a.x + metric->G2_23*a.y + metric->G3_23*a.z); + result.y = VDDX(vcn.x, a.y) + VDDY(vcn.y, a.y) + VDDZ(vcn.z, a.y); + result.y -= vcn.x * (metric->G1_12 * a.x + metric->G2_12 * a.y + metric->G3_12 * a.z); + result.y -= vcn.y * (metric->G1_22 * a.x + metric->G2_22 * a.y + metric->G3_22 * a.z); + result.y -= vcn.z * (metric->G1_23 * a.x + metric->G2_23 * a.y + metric->G3_23 * a.z); - result.z = VDDX(vcn.x, a.z, outloc) + VDDY(vcn.y, a.z, outloc) + VDDZ(vcn.z, a.z, outloc); - result.z -= vcn.x*(metric->G1_13*a.x + metric->G2_13*a.y + metric->G3_13*a.z); - result.z -= vcn.y*(metric->G1_23*a.x + metric->G2_23*a.y + metric->G3_23*a.z); - result.z -= vcn.z*(metric->G1_33*a.x + metric->G2_33*a.y + metric->G3_33*a.z); + result.z = VDDX(vcn.x, a.z) + VDDY(vcn.y, a.z) + VDDZ(vcn.z, a.z); + result.z -= vcn.x * (metric->G1_13 * a.x + metric->G2_13 * a.y + metric->G3_13 * a.z); + result.z -= vcn.y * (metric->G1_23 * a.x + metric->G2_23 * a.y + metric->G3_23 * a.z); + result.z -= vcn.z * (metric->G1_33 * a.x + metric->G2_33 * a.y + metric->G3_33 * a.z); result.covariant = true; - }else { - - result.x = VDDX(vcn.x, a.x, outloc) + VDDY(vcn.y, a.x, outloc) + VDDZ(vcn.z, a.x, outloc); - result.x += vcn.x*(metric->G1_11*a.x + metric->G1_12*a.y + metric->G1_13*a.z); - result.x += vcn.y*(metric->G1_12*a.x + metric->G1_22*a.y + metric->G1_23*a.z); - result.x += vcn.z*(metric->G1_13*a.x + metric->G1_23*a.y + metric->G1_33*a.z); - - result.y = VDDX(vcn.x, a.y, outloc) + VDDY(vcn.y, a.y, outloc) + VDDZ(vcn.z, a.y, outloc); - result.y += vcn.x*(metric->G2_11*a.x + metric->G2_12*a.y + metric->G2_13*a.z); - result.y += vcn.y*(metric->G2_12*a.x + metric->G2_22*a.y + metric->G2_23*a.z); - result.y += vcn.z*(metric->G2_13*a.x + metric->G2_23*a.y + metric->G2_33*a.z); - - result.z = VDDX(vcn.x, a.z, outloc) + VDDY(vcn.y, a.z, outloc) + VDDZ(vcn.z, a.z, outloc); - result.z += vcn.x*(metric->G3_11*a.x + metric->G3_12*a.y + metric->G3_13*a.z); - result.z += vcn.y*(metric->G3_12*a.x + metric->G3_22*a.y + metric->G3_23*a.z); - result.z += vcn.z*(metric->G3_13*a.x + metric->G3_23*a.y + metric->G3_33*a.z); + } else { + + result.x = VDDX(vcn.x, a.x) + VDDY(vcn.y, a.x) + VDDZ(vcn.z, a.x); + result.x += vcn.x * (metric->G1_11 * a.x + metric->G1_12 * a.y + metric->G1_13 * a.z); + result.x += vcn.y * (metric->G1_12 * a.x + metric->G1_22 * a.y + metric->G1_23 * a.z); + result.x += vcn.z * (metric->G1_13 * a.x + metric->G1_23 * a.y + metric->G1_33 * a.z); + + result.y = VDDX(vcn.x, a.y) + VDDY(vcn.y, a.y) + VDDZ(vcn.z, a.y); + result.y += vcn.x * (metric->G2_11 * a.x + metric->G2_12 * a.y + metric->G2_13 * a.z); + result.y += vcn.y * (metric->G2_12 * a.x + metric->G2_22 * a.y + metric->G2_23 * a.z); + result.y += vcn.z * (metric->G2_13 * a.x + metric->G2_23 * a.y + metric->G2_33 * a.z); + + result.z = VDDX(vcn.x, a.z) + VDDY(vcn.y, a.z) + VDDZ(vcn.z, a.z); + result.z += vcn.x * (metric->G3_11 * a.x + metric->G3_12 * a.y + metric->G3_13 * a.z); + result.z += vcn.y * (metric->G3_12 * a.x + metric->G3_22 * a.y + metric->G3_23 * a.z); + result.z += vcn.z * (metric->G3_13 * a.x + metric->G3_23 * a.y + metric->G3_33 * a.z); result.covariant = false; } + result.setLocation(v.getLocation()); + return result; } -const Vector3D V_dot_Grad(const Vector2D &v, const Vector3D &a, const CELL_LOC outloc) { - Mesh *localmesh = v.x.getMesh(); - Vector3D result(localmesh); - +const Vector3D V_dot_Grad(const Vector2D &v, const Vector3D &a) { TRACE("V_dot_Grad( Vector2D , Vector3D )"); - Coordinates *metric = localmesh->coordinates(outloc); + ASSERT1(v.getLocation() == a.getLocation()); + ASSERT1(v.getLocation() != CELL_VSHIFT); + + Vector3D result{v.x.getMesh()}; + + auto metric = v.x.getCoordinates(); Vector2D vcn = v; vcn.toContravariant(); - if(a.covariant) { - result.x = VDDX(vcn.x, a.x, outloc) + VDDY(vcn.y, a.x, outloc) + VDDZ(vcn.z, a.x, outloc); - result.x -= vcn.x*(metric->G1_11*a.x + metric->G2_11*a.y + metric->G3_11*a.z); - result.x -= vcn.y*(metric->G1_12*a.x + metric->G2_12*a.y + metric->G3_12*a.z); - result.x -= vcn.z*(metric->G1_13*a.x + metric->G2_13*a.y + metric->G3_13*a.z); + if (a.covariant) { + result.x = VDDX(vcn.x, a.x) + VDDY(vcn.y, a.x) + VDDZ(vcn.z, a.x); + result.x -= vcn.x * (metric->G1_11 * a.x + metric->G2_11 * a.y + metric->G3_11 * a.z); + result.x -= vcn.y * (metric->G1_12 * a.x + metric->G2_12 * a.y + metric->G3_12 * a.z); + result.x -= vcn.z * (metric->G1_13 * a.x + metric->G2_13 * a.y + metric->G3_13 * a.z); - result.y = VDDX(vcn.x, a.y, outloc) + VDDY(vcn.y, a.y, outloc) + VDDZ(vcn.z, a.y, outloc); - result.y -= vcn.x*(metric->G1_12*a.x + metric->G2_12*a.y + metric->G3_12*a.z); - result.y -= vcn.y*(metric->G1_22*a.x + metric->G2_22*a.y + metric->G3_22*a.z); - result.y -= vcn.z*(metric->G1_23*a.x + metric->G2_23*a.y + metric->G3_23*a.z); + result.y = VDDX(vcn.x, a.y) + VDDY(vcn.y, a.y) + VDDZ(vcn.z, a.y); + result.y -= vcn.x * (metric->G1_12 * a.x + metric->G2_12 * a.y + metric->G3_12 * a.z); + result.y -= vcn.y * (metric->G1_22 * a.x + metric->G2_22 * a.y + metric->G3_22 * a.z); + result.y -= vcn.z * (metric->G1_23 * a.x + metric->G2_23 * a.y + metric->G3_23 * a.z); - result.z = VDDX(vcn.x, a.z, outloc) + VDDY(vcn.y, a.z, outloc) + VDDZ(vcn.z, a.z, outloc); - result.z -= vcn.x*(metric->G1_13*a.x + metric->G2_13*a.y + metric->G3_13*a.z); - result.z -= vcn.y*(metric->G1_23*a.x + metric->G2_23*a.y + metric->G3_23*a.z); - result.z -= vcn.z*(metric->G1_33*a.x + metric->G2_33*a.y + metric->G3_33*a.z); + result.z = VDDX(vcn.x, a.z) + VDDY(vcn.y, a.z) + VDDZ(vcn.z, a.z); + result.z -= vcn.x * (metric->G1_13 * a.x + metric->G2_13 * a.y + metric->G3_13 * a.z); + result.z -= vcn.y * (metric->G1_23 * a.x + metric->G2_23 * a.y + metric->G3_23 * a.z); + result.z -= vcn.z * (metric->G1_33 * a.x + metric->G2_33 * a.y + metric->G3_33 * a.z); result.covariant = true; - }else { - result.x = VDDX(vcn.x, a.x, outloc) + VDDY(vcn.y, a.x, outloc) + VDDZ(vcn.z, a.x, outloc); - result.x += vcn.x*(metric->G1_11*a.x + metric->G1_12*a.y + metric->G1_13*a.z); - result.x += vcn.y*(metric->G1_12*a.x + metric->G1_22*a.y + metric->G1_23*a.z); - result.x += vcn.z*(metric->G1_13*a.x + metric->G1_23*a.y + metric->G1_33*a.z); - - result.y = VDDX(vcn.x, a.y, outloc) + VDDY(vcn.y, a.y, outloc) + VDDZ(vcn.z, a.y, outloc); - result.y += vcn.x*(metric->G2_11*a.x + metric->G2_12*a.y + metric->G2_13*a.z); - result.y += vcn.y*(metric->G2_12*a.x + metric->G2_22*a.y + metric->G2_23*a.z); - result.y += vcn.z*(metric->G2_13*a.x + metric->G2_23*a.y + metric->G2_33*a.z); - - result.z = VDDX(vcn.x, a.z, outloc) + VDDY(vcn.y, a.z, outloc) + VDDZ(vcn.z, a.z, outloc); - result.z += vcn.x*(metric->G3_11*a.x + metric->G3_12*a.y + metric->G3_13*a.z); - result.z += vcn.y*(metric->G3_12*a.x + metric->G3_22*a.y + metric->G3_23*a.z); - result.z += vcn.z*(metric->G3_13*a.x + metric->G3_23*a.y + metric->G3_33*a.z); + } else { + result.x = VDDX(vcn.x, a.x) + VDDY(vcn.y, a.x) + VDDZ(vcn.z, a.x); + result.x += vcn.x * (metric->G1_11 * a.x + metric->G1_12 * a.y + metric->G1_13 * a.z); + result.x += vcn.y * (metric->G1_12 * a.x + metric->G1_22 * a.y + metric->G1_23 * a.z); + result.x += vcn.z * (metric->G1_13 * a.x + metric->G1_23 * a.y + metric->G1_33 * a.z); + + result.y = VDDX(vcn.x, a.y) + VDDY(vcn.y, a.y) + VDDZ(vcn.z, a.y); + result.y += vcn.x * (metric->G2_11 * a.x + metric->G2_12 * a.y + metric->G2_13 * a.z); + result.y += vcn.y * (metric->G2_12 * a.x + metric->G2_22 * a.y + metric->G2_23 * a.z); + result.y += vcn.z * (metric->G2_13 * a.x + metric->G2_23 * a.y + metric->G2_33 * a.z); + + result.z = VDDX(vcn.x, a.z) + VDDY(vcn.y, a.z) + VDDZ(vcn.z, a.z); + result.z += vcn.x * (metric->G3_11 * a.x + metric->G3_12 * a.y + metric->G3_13 * a.z); + result.z += vcn.y * (metric->G3_12 * a.x + metric->G3_22 * a.y + metric->G3_23 * a.z); + result.z += vcn.z * (metric->G3_13 * a.x + metric->G3_23 * a.y + metric->G3_33 * a.z); result.covariant = false; } + result.setLocation(v.getLocation()); + return result; } -const Vector3D V_dot_Grad(const Vector3D &v, const Vector2D &a, const CELL_LOC outloc) { - Mesh *localmesh = v.x.getMesh(); - Vector3D result(localmesh); - +const Vector3D V_dot_Grad(const Vector3D &v, const Vector2D &a) { TRACE("V_dot_Grad( Vector3D , Vector2D )"); - Coordinates *metric = localmesh->coordinates(outloc); + ASSERT1(v.getLocation() == a.getLocation()); + ASSERT1(v.getLocation() != CELL_VSHIFT); + + Vector3D result{v.x.getMesh()}; + + auto metric = v.x.getCoordinates(); Vector3D vcn = v; vcn.toContravariant(); - if(a.covariant) { - result.x = VDDX(vcn.x, a.x, outloc) + VDDY(vcn.y, a.x, outloc) + VDDZ(vcn.z, a.x, outloc); - result.x -= vcn.x*(metric->G1_11*a.x + metric->G2_11*a.y + metric->G3_11*a.z); - result.x -= vcn.y*(metric->G1_12*a.x + metric->G2_12*a.y + metric->G3_12*a.z); - result.x -= vcn.z*(metric->G1_13*a.x + metric->G2_13*a.y + metric->G3_13*a.z); + if (a.covariant) { + result.x = VDDX(vcn.x, a.x) + VDDY(vcn.y, a.x) + VDDZ(vcn.z, a.x); + result.x -= vcn.x * (metric->G1_11 * a.x + metric->G2_11 * a.y + metric->G3_11 * a.z); + result.x -= vcn.y * (metric->G1_12 * a.x + metric->G2_12 * a.y + metric->G3_12 * a.z); + result.x -= vcn.z * (metric->G1_13 * a.x + metric->G2_13 * a.y + metric->G3_13 * a.z); - result.y = VDDX(vcn.x, a.y, outloc) + VDDY(vcn.y, a.y, outloc) + VDDZ(vcn.z, a.y, outloc); - result.y -= vcn.x*(metric->G1_12*a.x + metric->G2_12*a.y + metric->G3_12*a.z); - result.y -= vcn.y*(metric->G1_22*a.x + metric->G2_22*a.y + metric->G3_22*a.z); - result.y -= vcn.z*(metric->G1_23*a.x + metric->G2_23*a.y + metric->G3_23*a.z); + result.y = VDDX(vcn.x, a.y) + VDDY(vcn.y, a.y) + VDDZ(vcn.z, a.y); + result.y -= vcn.x * (metric->G1_12 * a.x + metric->G2_12 * a.y + metric->G3_12 * a.z); + result.y -= vcn.y * (metric->G1_22 * a.x + metric->G2_22 * a.y + metric->G3_22 * a.z); + result.y -= vcn.z * (metric->G1_23 * a.x + metric->G2_23 * a.y + metric->G3_23 * a.z); - result.z = VDDX(vcn.x, a.z, outloc) + VDDY(vcn.y, a.z, outloc) + VDDZ(vcn.z, a.z, outloc); - result.z -= vcn.x*(metric->G1_13*a.x + metric->G2_13*a.y + metric->G3_13*a.z); - result.z -= vcn.y*(metric->G1_23*a.x + metric->G2_23*a.y + metric->G3_23*a.z); - result.z -= vcn.z*(metric->G1_33*a.x + metric->G2_33*a.y + metric->G3_33*a.z); + result.z = VDDX(vcn.x, a.z) + VDDY(vcn.y, a.z) + VDDZ(vcn.z, a.z); + result.z -= vcn.x * (metric->G1_13 * a.x + metric->G2_13 * a.y + metric->G3_13 * a.z); + result.z -= vcn.y * (metric->G1_23 * a.x + metric->G2_23 * a.y + metric->G3_23 * a.z); + result.z -= vcn.z * (metric->G1_33 * a.x + metric->G2_33 * a.y + metric->G3_33 * a.z); result.covariant = true; - }else { - result.x = VDDX(vcn.x, a.x, outloc) + VDDY(vcn.y, a.x, outloc) + VDDZ(vcn.z, a.x, outloc); - result.x += vcn.x*(metric->G1_11*a.x + metric->G1_12*a.y + metric->G1_13*a.z); - result.x += vcn.y*(metric->G1_12*a.x + metric->G1_22*a.y + metric->G1_23*a.z); - result.x += vcn.z*(metric->G1_13*a.x + metric->G1_23*a.y + metric->G1_33*a.z); - - result.y = VDDX(vcn.x, a.y, outloc) + VDDY(vcn.y, a.y, outloc) + VDDZ(vcn.z, a.y, outloc); - result.y += vcn.x*(metric->G2_11*a.x + metric->G2_12*a.y + metric->G2_13*a.z); - result.y += vcn.y*(metric->G2_12*a.x + metric->G2_22*a.y + metric->G2_23*a.z); - result.y += vcn.z*(metric->G2_13*a.x + metric->G2_23*a.y + metric->G2_33*a.z); - - result.z = VDDX(vcn.x, a.z, outloc) + VDDY(vcn.y, a.z, outloc) + VDDZ(vcn.z, a.z, outloc); - result.z += vcn.x*(metric->G3_11*a.x + metric->G3_12*a.y + metric->G3_13*a.z); - result.z += vcn.y*(metric->G3_12*a.x + metric->G3_22*a.y + metric->G3_23*a.z); - result.z += vcn.z*(metric->G3_13*a.x + metric->G3_23*a.y + metric->G3_33*a.z); + } else { + result.x = VDDX(vcn.x, a.x) + VDDY(vcn.y, a.x) + VDDZ(vcn.z, a.x); + result.x += vcn.x * (metric->G1_11 * a.x + metric->G1_12 * a.y + metric->G1_13 * a.z); + result.x += vcn.y * (metric->G1_12 * a.x + metric->G1_22 * a.y + metric->G1_23 * a.z); + result.x += vcn.z * (metric->G1_13 * a.x + metric->G1_23 * a.y + metric->G1_33 * a.z); + + result.y = VDDX(vcn.x, a.y) + VDDY(vcn.y, a.y) + VDDZ(vcn.z, a.y); + result.y += vcn.x * (metric->G2_11 * a.x + metric->G2_12 * a.y + metric->G2_13 * a.z); + result.y += vcn.y * (metric->G2_12 * a.x + metric->G2_22 * a.y + metric->G2_23 * a.z); + result.y += vcn.z * (metric->G2_13 * a.x + metric->G2_23 * a.y + metric->G2_33 * a.z); + + result.z = VDDX(vcn.x, a.z) + VDDY(vcn.y, a.z) + VDDZ(vcn.z, a.z); + result.z += vcn.x * (metric->G3_11 * a.x + metric->G3_12 * a.y + metric->G3_13 * a.z); + result.z += vcn.y * (metric->G3_12 * a.x + metric->G3_22 * a.y + metric->G3_23 * a.z); + result.z += vcn.z * (metric->G3_13 * a.x + metric->G3_23 * a.y + metric->G3_33 * a.z); result.covariant = false; } + result.setLocation(v.getLocation()); + return result; } -const Vector3D V_dot_Grad(const Vector3D &v, const Vector3D &a, const CELL_LOC outloc) { - Mesh *localmesh = v.x.getMesh(); - Vector3D result(localmesh); - +const Vector3D V_dot_Grad(const Vector3D &v, const Vector3D &a) { TRACE("V_dot_Grad( Vector3D , Vector3D )"); - Coordinates *metric = localmesh->coordinates(outloc); + ASSERT1(v.getLocation() == a.getLocation()); + ASSERT1(v.getLocation() != CELL_VSHIFT); + + Vector3D result{v.x.getMesh()}; + + auto metric = v.x.getCoordinates(); Vector3D vcn = v; vcn.toContravariant(); - if(a.covariant) { - result.x = VDDX(vcn.x, a.x, outloc) + VDDY(vcn.y, a.x, outloc) + VDDZ(vcn.z, a.x, outloc); - result.x -= vcn.x*(metric->G1_11*a.x + metric->G2_11*a.y + metric->G3_11*a.z); - result.x -= vcn.y*(metric->G1_12*a.x + metric->G2_12*a.y + metric->G3_12*a.z); - result.x -= vcn.z*(metric->G1_13*a.x + metric->G2_13*a.y + metric->G3_13*a.z); + if (a.covariant) { + result.x = VDDX(vcn.x, a.x) + VDDY(vcn.y, a.x) + VDDZ(vcn.z, a.x); + result.x -= vcn.x * (metric->G1_11 * a.x + metric->G2_11 * a.y + metric->G3_11 * a.z); + result.x -= vcn.y * (metric->G1_12 * a.x + metric->G2_12 * a.y + metric->G3_12 * a.z); + result.x -= vcn.z * (metric->G1_13 * a.x + metric->G2_13 * a.y + metric->G3_13 * a.z); - result.y = VDDX(vcn.x, a.y, outloc) + VDDY(vcn.y, a.y, outloc) + VDDZ(vcn.z, a.y, outloc); - result.y -= vcn.x*(metric->G1_12*a.x + metric->G2_12*a.y + metric->G3_12*a.z); - result.y -= vcn.y*(metric->G1_22*a.x + metric->G2_22*a.y + metric->G3_22*a.z); - result.y -= vcn.z*(metric->G1_23*a.x + metric->G2_23*a.y + metric->G3_23*a.z); + result.y = VDDX(vcn.x, a.y) + VDDY(vcn.y, a.y) + VDDZ(vcn.z, a.y); + result.y -= vcn.x * (metric->G1_12 * a.x + metric->G2_12 * a.y + metric->G3_12 * a.z); + result.y -= vcn.y * (metric->G1_22 * a.x + metric->G2_22 * a.y + metric->G3_22 * a.z); + result.y -= vcn.z * (metric->G1_23 * a.x + metric->G2_23 * a.y + metric->G3_23 * a.z); - result.z = VDDX(vcn.x, a.z, outloc) + VDDY(vcn.y, a.z, outloc) + VDDZ(vcn.z, a.z, outloc); - result.z -= vcn.x*(metric->G1_13*a.x + metric->G2_13*a.y + metric->G3_13*a.z); - result.z -= vcn.y*(metric->G1_23*a.x + metric->G2_23*a.y + metric->G3_23*a.z); - result.z -= vcn.z*(metric->G1_33*a.x + metric->G2_33*a.y + metric->G3_33*a.z); + result.z = VDDX(vcn.x, a.z) + VDDY(vcn.y, a.z) + VDDZ(vcn.z, a.z); + result.z -= vcn.x * (metric->G1_13 * a.x + metric->G2_13 * a.y + metric->G3_13 * a.z); + result.z -= vcn.y * (metric->G1_23 * a.x + metric->G2_23 * a.y + metric->G3_23 * a.z); + result.z -= vcn.z * (metric->G1_33 * a.x + metric->G2_33 * a.y + metric->G3_33 * a.z); result.covariant = true; - }else { - result.x = VDDX(vcn.x, a.x, outloc) + VDDY(vcn.y, a.x, outloc) + VDDZ(vcn.z, a.x, outloc); - result.x += vcn.x*(metric->G1_11*a.x + metric->G1_12*a.y + metric->G1_13*a.z); - result.x += vcn.y*(metric->G1_12*a.x + metric->G1_22*a.y + metric->G1_23*a.z); - result.x += vcn.z*(metric->G1_13*a.x + metric->G1_23*a.y + metric->G1_33*a.z); - - result.y = VDDX(vcn.x, a.y, outloc) + VDDY(vcn.y, a.y, outloc) + VDDZ(vcn.z, a.y, outloc); - result.y += vcn.x*(metric->G2_11*a.x + metric->G2_12*a.y + metric->G2_13*a.z); - result.y += vcn.y*(metric->G2_12*a.x + metric->G2_22*a.y + metric->G2_23*a.z); - result.y += vcn.z*(metric->G2_13*a.x + metric->G2_23*a.y + metric->G2_33*a.z); - - result.z = VDDX(vcn.x, a.z, outloc) + VDDY(vcn.y, a.z, outloc) + VDDZ(vcn.z, a.z, outloc); - result.z += vcn.x*(metric->G3_11*a.x + metric->G3_12*a.y + metric->G3_13*a.z); - result.z += vcn.y*(metric->G3_12*a.x + metric->G3_22*a.y + metric->G3_23*a.z); - result.z += vcn.z*(metric->G3_13*a.x + metric->G3_23*a.y + metric->G3_33*a.z); + } else { + result.x = VDDX(vcn.x, a.x) + VDDY(vcn.y, a.x) + VDDZ(vcn.z, a.x); + result.x += vcn.x * (metric->G1_11 * a.x + metric->G1_12 * a.y + metric->G1_13 * a.z); + result.x += vcn.y * (metric->G1_12 * a.x + metric->G1_22 * a.y + metric->G1_23 * a.z); + result.x += vcn.z * (metric->G1_13 * a.x + metric->G1_23 * a.y + metric->G1_33 * a.z); + + result.y = VDDX(vcn.x, a.y) + VDDY(vcn.y, a.y) + VDDZ(vcn.z, a.y); + result.y += vcn.x * (metric->G2_11 * a.x + metric->G2_12 * a.y + metric->G2_13 * a.z); + result.y += vcn.y * (metric->G2_12 * a.x + metric->G2_22 * a.y + metric->G2_23 * a.z); + result.y += vcn.z * (metric->G2_13 * a.x + metric->G2_23 * a.y + metric->G2_33 * a.z); + + result.z = VDDX(vcn.x, a.z) + VDDY(vcn.y, a.z) + VDDZ(vcn.z, a.z); + result.z += vcn.x * (metric->G3_11 * a.x + metric->G3_12 * a.y + metric->G3_13 * a.z); + result.z += vcn.y * (metric->G3_12 * a.x + metric->G3_22 * a.y + metric->G3_23 * a.z); + result.z += vcn.z * (metric->G3_13 * a.x + metric->G3_23 * a.y + metric->G3_33 * a.z); result.covariant = false; } + result.setLocation(v.getLocation()); + return result; } - - diff --git a/src/field/vector2d.cxx b/src/field/vector2d.cxx index e94e26b512..5677b4cd1e 100644 --- a/src/field/vector2d.cxx +++ b/src/field/vector2d.cxx @@ -36,10 +36,12 @@ #include Vector2D::Vector2D(Mesh *localmesh) - : x(localmesh), y(localmesh), z(localmesh), covariant(true), deriv(nullptr), location(CELL_CENTRE) {} + : FieldData(localmesh), x(localmesh), y(localmesh), z(localmesh), + covariant(true), deriv(nullptr), location(CELL_CENTRE) {} Vector2D::Vector2D(const Vector2D &f) - : x(f.x), y(f.y), z(f.z), covariant(f.covariant), deriv(nullptr), location(CELL_CENTRE) {} + : FieldData(f.fielddatamesh), x(f.x), y(f.y), z(f.z), covariant(f.covariant), + deriv(nullptr), location(f.getLocation()) {} Vector2D::~Vector2D() { if (deriv != nullptr) { @@ -61,13 +63,13 @@ void Vector2D::toCovariant() { Coordinates *metric_x, *metric_y, *metric_z; if (location == CELL_VSHIFT) { - metric_x = localmesh->coordinates(CELL_XLOW); - metric_y = localmesh->coordinates(CELL_YLOW); - metric_z = localmesh->coordinates(CELL_ZLOW); + metric_x = localmesh->getCoordinates(CELL_XLOW); + metric_y = localmesh->getCoordinates(CELL_YLOW); + metric_z = localmesh->getCoordinates(CELL_ZLOW); } else { - metric_x = localmesh->coordinates(location); - metric_y = localmesh->coordinates(location); - metric_z = localmesh->coordinates(location); + metric_x = localmesh->getCoordinates(location); + metric_y = localmesh->getCoordinates(location); + metric_z = localmesh->getCoordinates(location); } // multiply by g_{ij} @@ -91,13 +93,13 @@ void Vector2D::toContravariant() { Coordinates *metric_x, *metric_y, *metric_z; if (location == CELL_VSHIFT) { - metric_x = localmesh->coordinates(CELL_XLOW); - metric_y = localmesh->coordinates(CELL_YLOW); - metric_z = localmesh->coordinates(CELL_ZLOW); + metric_x = localmesh->getCoordinates(CELL_XLOW); + metric_y = localmesh->getCoordinates(CELL_YLOW); + metric_z = localmesh->getCoordinates(CELL_ZLOW); } else { - metric_x = localmesh->coordinates(location); - metric_y = localmesh->coordinates(location); - metric_z = localmesh->coordinates(location); + metric_x = localmesh->getCoordinates(location); + metric_y = localmesh->getCoordinates(location); + metric_z = localmesh->getCoordinates(location); } // multiply by g_{ij} @@ -147,10 +149,14 @@ Vector2D* Vector2D::timeDeriv() { /////////////////// ASSIGNMENT //////////////////// Vector2D & Vector2D::operator=(const Vector2D &rhs) { + fielddatamesh = rhs.fielddatamesh; + x = rhs.x; y = rhs.y; z = rhs.z; + setLocation(rhs.getLocation()); + covariant = rhs.covariant; return *this; @@ -336,7 +342,7 @@ const Field2D 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->coordinates(location); + Coordinates *metric = localmesh->getCoordinates(location); if(covariant) { // Both covariant @@ -388,16 +394,32 @@ CELL_LOC Vector2D::getLocation() const { } void Vector2D::setLocation(CELL_LOC loc) { - location = loc; - if(loc == CELL_VSHIFT) { - x.setLocation(CELL_XLOW); - y.setLocation(CELL_YLOW); - z.setLocation(CELL_ZLOW); + TRACE("Vector2D::setLocation"); + if (loc == CELL_DEFAULT) { + loc = CELL_CENTRE; + } + + if (x.getMesh()->StaggerGrids) { + if (loc == CELL_VSHIFT) { + x.setLocation(CELL_XLOW); + y.setLocation(CELL_YLOW); + z.setLocation(CELL_ZLOW); + } else { + x.setLocation(loc); + y.setLocation(loc); + z.setLocation(loc); + } } else { - x.setLocation(loc); - y.setLocation(loc); - z.setLocation(loc); +#if CHECK > 0 + if (loc != CELL_CENTRE) { + throw BoutException("Vector2D: Trying to set off-centre location on " + "non-staggered grid\n" + " Did you mean to enable staggered grids?"); + } +#endif } + + location = loc; } /*************************************************************** diff --git a/src/field/vector3d.cxx b/src/field/vector3d.cxx index c7df254d0e..28ada267e5 100644 --- a/src/field/vector3d.cxx +++ b/src/field/vector3d.cxx @@ -37,10 +37,12 @@ #include Vector3D::Vector3D(Mesh *localmesh) - : x(localmesh), y(localmesh), z(localmesh), covariant(true), deriv(nullptr), location(CELL_CENTRE) {} + : FieldData(localmesh), x(localmesh), y(localmesh), z(localmesh), + covariant(true), deriv(nullptr), location(CELL_CENTRE) {} Vector3D::Vector3D(const Vector3D &f) - : x(f.x), y(f.y), z(f.z), covariant(f.covariant), deriv(nullptr), location(CELL_CENTRE) {} + : FieldData(f.fielddatamesh), x(f.x), y(f.y), z(f.z), covariant(f.covariant), + deriv(nullptr), location(f.getLocation()) {} Vector3D::~Vector3D() { if (deriv != nullptr) { @@ -62,13 +64,13 @@ void Vector3D::toCovariant() { Coordinates *metric_x, *metric_y, *metric_z; if (location == CELL_VSHIFT) { - metric_x = localmesh->coordinates(CELL_XLOW); - metric_y = localmesh->coordinates(CELL_YLOW); - metric_z = localmesh->coordinates(CELL_ZLOW); + metric_x = localmesh->getCoordinates(CELL_XLOW); + metric_y = localmesh->getCoordinates(CELL_YLOW); + metric_z = localmesh->getCoordinates(CELL_ZLOW); } else { - metric_x = localmesh->coordinates(location); - metric_y = localmesh->coordinates(location); - metric_z = localmesh->coordinates(location); + metric_x = localmesh->getCoordinates(location); + metric_y = localmesh->getCoordinates(location); + metric_z = localmesh->getCoordinates(location); } // multiply by g_{ij} @@ -91,13 +93,13 @@ void Vector3D::toContravariant() { Coordinates *metric_x, *metric_y, *metric_z; if (location == CELL_VSHIFT) { - metric_x = localmesh->coordinates(CELL_XLOW); - metric_y = localmesh->coordinates(CELL_YLOW); - metric_z = localmesh->coordinates(CELL_ZLOW); + metric_x = localmesh->getCoordinates(CELL_XLOW); + metric_y = localmesh->getCoordinates(CELL_YLOW); + metric_z = localmesh->getCoordinates(CELL_ZLOW); } else { - metric_x = localmesh->coordinates(location); - metric_y = localmesh->coordinates(location); - metric_z = localmesh->coordinates(location); + metric_x = localmesh->getCoordinates(location); + metric_y = localmesh->getCoordinates(location); + metric_z = localmesh->getCoordinates(location); } // multiply by g_{ij} @@ -148,22 +150,29 @@ Vector3D* Vector3D::timeDeriv() { /////////////////// ASSIGNMENT //////////////////// Vector3D & Vector3D::operator=(const Vector3D &rhs) { + fielddatamesh = rhs.fielddatamesh; + x = rhs.x; y = rhs.y; z = rhs.z; covariant = rhs.covariant; + setLocation(rhs.getLocation()); return *this; } Vector3D & Vector3D::operator=(const Vector2D &rhs) { + fielddatamesh = rhs.x.getDataMesh(); + x = rhs.x; y = rhs.y; z = rhs.z; covariant = rhs.covariant; + setLocation(rhs.getLocation()); + return *this; } @@ -325,7 +334,7 @@ Vector3D & Vector3D::operator/=(const Field3D &rhs) v1 lco = lhs; \ lco.toCovariant(); \ \ - Coordinates *metric = localmesh->coordinates(lhs.getLocation()); \ + Coordinates *metric = localmesh->getCoordinates(lhs.getLocation()); \ \ /* calculate contravariant components of cross-product */ \ result.x = (lco.y * rco.z - lco.z * rco.y) / metric->J; \ @@ -436,7 +445,7 @@ const Field3D Vector3D::operator*(const Vector3D &rhs) const { }else { // Both are covariant or contravariant - Coordinates *metric = mesh->coordinates(location); + Coordinates *metric = mesh->getCoordinates(location); if(covariant) { // Both covariant @@ -515,16 +524,32 @@ CELL_LOC Vector3D::getLocation() const { } void Vector3D::setLocation(CELL_LOC loc) { - location = loc; - if(loc == CELL_VSHIFT) { - x.setLocation(CELL_XLOW); - y.setLocation(CELL_YLOW); - z.setLocation(CELL_ZLOW); + TRACE("Vector3D::setLocation"); + if (loc == CELL_DEFAULT) { + loc = CELL_CENTRE; + } + + if (x.getMesh()->StaggerGrids) { + if (loc == CELL_VSHIFT) { + x.setLocation(CELL_XLOW); + y.setLocation(CELL_YLOW); + z.setLocation(CELL_ZLOW); + } else { + x.setLocation(loc); + y.setLocation(loc); + z.setLocation(loc); + } } else { - x.setLocation(loc); - y.setLocation(loc); - z.setLocation(loc); +#if CHECK > 0 + if (loc != CELL_CENTRE) { + throw BoutException("Vector3D: Trying to set off-centre location on " + "non-staggered grid\n" + " Did you mean to enable staggered grids?"); + } +#endif } + + location = loc; } /*************************************************************** diff --git a/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx b/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx index 7070232f85..223617de3c 100644 --- a/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx +++ b/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx @@ -94,7 +94,7 @@ const FieldPerp LaplaceCyclic::solve(const FieldPerp &rhs, const FieldPerp &x0) FieldPerp x(mesh); // Result x.allocate(); - Coordinates *coord = mesh->coordinates(location); + Coordinates *coord = mesh->getCoordinates(location); int jy = rhs.getIndex(); // Get the Y index x.setIndex(jy); @@ -257,7 +257,7 @@ const Field3D LaplaceCyclic::solve(const Field3D &rhs, const Field3D &x0) { Field3D x(mesh); // Result x.allocate(); - Coordinates *coord = mesh->coordinates(); + Coordinates *coord = mesh->getCoordinates(); // Get the width of the boundary diff --git a/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx b/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx index 5170c0d031..17e0e6b127 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx +++ b/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx @@ -208,7 +208,7 @@ const FieldPerp LaplaceMultigrid::solve(const FieldPerp &b_in, const FieldPerp & Mesh *mesh = b_in.getMesh(); BoutReal t0,t1; - Coordinates *coords = mesh->coordinates(location); + Coordinates *coords = mesh->getCoordinates(location); yindex = b_in.getIndex(); int level = kMG->mglevel-1; @@ -554,7 +554,7 @@ void LaplaceMultigrid::generateMatrixF(int level) { // Set (fine-level) matrix entries - Coordinates *coords = mesh->coordinates(location); + Coordinates *coords = mesh->getCoordinates(location); BoutReal *mat; mat = kMG->matmg[level]; int llx = kMG->lnx[level]; diff --git a/src/invert/laplace/impls/naulin/naulin_laplace.cxx b/src/invert/laplace/impls/naulin/naulin_laplace.cxx index faad970129..fa065b0f12 100644 --- a/src/invert/laplace/impls/naulin/naulin_laplace.cxx +++ b/src/invert/laplace/impls/naulin/naulin_laplace.cxx @@ -172,7 +172,7 @@ const Field3D LaplaceNaulin::solve(const Field3D &rhs, const Field3D &x0) { ASSERT1(Acoef.getLocation() == location); Mesh *mesh = rhs.getMesh(); - Coordinates *coords = mesh->coordinates(location); + Coordinates *coords = mesh->getCoordinates(location); Field3D x(x0); // Result Field3D rhsOverD = rhs/Dcoef; diff --git a/src/invert/laplace/impls/pdd/pdd.cxx b/src/invert/laplace/impls/pdd/pdd.cxx index 2fe65814f8..f71b551ccb 100644 --- a/src/invert/laplace/impls/pdd/pdd.cxx +++ b/src/invert/laplace/impls/pdd/pdd.cxx @@ -160,7 +160,7 @@ void LaplacePDD::start(const FieldPerp &b, PDD_data &data) { /// Create the matrices to be inverted (one for each z point) - BoutReal kwaveFactor = 2.0 * PI / mesh->coordinates(location)->zlength(); + BoutReal kwaveFactor = 2.0 * PI / mesh->getCoordinates(location)->zlength(); /// Set matrix elements for (int kz = 0; kz <= maxmode; kz++) { diff --git a/src/invert/laplace/impls/petsc/petsc_laplace.cxx b/src/invert/laplace/impls/petsc/petsc_laplace.cxx index e7bff57309..27f01a3161 100644 --- a/src/invert/laplace/impls/petsc/petsc_laplace.cxx +++ b/src/invert/laplace/impls/petsc/petsc_laplace.cxx @@ -361,7 +361,7 @@ const FieldPerp LaplacePetsc::solve(const FieldPerp &b, const FieldPerp &x0) { #endif // Get the metric tensor - Coordinates* coord = mesh->coordinates(location); + Coordinates* coord = mesh->getCoordinates(location); int y = b.getIndex(); // Get the Y index sol.setIndex(y); // Initialize the solution field. @@ -935,7 +935,7 @@ void LaplacePetsc::Element(int i, int x, int z, */ void LaplacePetsc::Coeffs( int x, int y, int z, BoutReal &coef1, BoutReal &coef2, BoutReal &coef3, BoutReal &coef4, BoutReal &coef5 ) { - Coordinates *coord = mesh->coordinates(location); // Get metric tensor + Coordinates *coord = mesh->getCoordinates(location); // Get metric tensor coef1 = coord->g11(x,y); // X 2nd derivative coefficient coef2 = coord->g33(x,y); // Z 2nd derivative coefficient diff --git a/src/invert/laplace/impls/serial_band/serial_band.cxx b/src/invert/laplace/impls/serial_band/serial_band.cxx index d4871d38ec..f2dfa04a66 100644 --- a/src/invert/laplace/impls/serial_band/serial_band.cxx +++ b/src/invert/laplace/impls/serial_band/serial_band.cxx @@ -86,7 +86,7 @@ const FieldPerp LaplaceSerialBand::solve(const FieldPerp &b, const FieldPerp &x0 int jy = b.getIndex(); x.setIndex(jy); - Coordinates *coord = mesh->coordinates(location); + Coordinates *coord = mesh->getCoordinates(location); int ncz = mesh->LocalNz; int ncx = mesh->LocalNx-1; diff --git a/src/invert/laplace/impls/serial_tri/serial_tri.cxx b/src/invert/laplace/impls/serial_tri/serial_tri.cxx index 8f36b14e8e..7080f18b31 100644 --- a/src/invert/laplace/impls/serial_tri/serial_tri.cxx +++ b/src/invert/laplace/impls/serial_tri/serial_tri.cxx @@ -82,7 +82,7 @@ const FieldPerp LaplaceSerialTri::solve(const FieldPerp &b, const FieldPerp &x0) int ncz = mesh->LocalNz; // No of z pnts int ncx = mesh->LocalNx; // No of x pnts - BoutReal kwaveFactor = 2.0 * PI / mesh->coordinates(location)->zlength(); + BoutReal kwaveFactor = 2.0 * PI / mesh->getCoordinates(location)->zlength(); // Setting the width of the boundary. // NOTE: The default is a width of 2 guard cells diff --git a/src/invert/laplace/impls/shoot/shoot_laplace.cxx b/src/invert/laplace/impls/shoot/shoot_laplace.cxx index 2470b0ab52..0db36a3c65 100644 --- a/src/invert/laplace/impls/shoot/shoot_laplace.cxx +++ b/src/invert/laplace/impls/shoot/shoot_laplace.cxx @@ -76,7 +76,7 @@ const FieldPerp LaplaceShoot::solve(const FieldPerp &rhs) { int jy = rhs.getIndex(); // Get the Y index x.setIndex(jy); - Coordinates *coord = mesh->coordinates(location); + Coordinates *coord = mesh->getCoordinates(location); // Get the width of the boundary diff --git a/src/invert/laplace/impls/spt/spt.cxx b/src/invert/laplace/impls/spt/spt.cxx index 5c5b019186..b7867a87d5 100644 --- a/src/invert/laplace/impls/spt/spt.cxx +++ b/src/invert/laplace/impls/spt/spt.cxx @@ -288,7 +288,7 @@ int LaplaceSPT::start(const FieldPerp &b, SPT_data &data) { data.bk(kz, ix) = dc1d[kz]; } - BoutReal kwaveFactor = 2.0 * PI / mesh->coordinates(location)->zlength(); + BoutReal kwaveFactor = 2.0 * PI / mesh->getCoordinates(location)->zlength(); /// Set matrix elements for (int kz = 0; kz <= maxmode; kz++) { diff --git a/src/invert/laplace/invert_laplace.cxx b/src/invert/laplace/invert_laplace.cxx index 4853b9f501..c9478eb20d 100644 --- a/src/invert/laplace/invert_laplace.cxx +++ b/src/invert/laplace/invert_laplace.cxx @@ -80,7 +80,7 @@ Laplacian::Laplacian(Options *options, const CELL_LOC loc) : location(loc) { OPTION(options, low_mem, false); OPTION(options, nonuniform, - mesh->coordinates(location)->non_uniform); // Default is the mesh setting + mesh->getCoordinates(location)->non_uniform); // Default is the mesh setting OPTION(options, all_terms, true); // Include first derivative terms @@ -249,7 +249,7 @@ void Laplacian::tridagCoefs(int jx, int jy, int jz, ASSERT1(ccoef == nullptr || ccoef->getLocation() == loc); ASSERT1(d == nullptr || d->getLocation() == loc); - Coordinates *coord = mesh->coordinates(loc); + Coordinates *coord = mesh->getCoordinates(loc); BoutReal kwave=jz*2.0*PI/coord->zlength(); // wave number is 1/[rad] @@ -296,7 +296,7 @@ void Laplacian::tridagCoefs(int jx, int jy, BoutReal kwave, BoutReal coef1, coef2, coef3, coef4, coef5; - Coordinates *coord = mesh->coordinates(loc); + Coordinates *coord = mesh->getCoordinates(loc); coef1=coord->g11(jx,jy); ///< X 2nd derivative coefficient coef2=coord->g33(jx,jy); ///< Z 2nd derivative coefficient @@ -361,7 +361,7 @@ void Laplacian::tridagMatrix(dcomplex **avec, dcomplex **bvec, dcomplex **cvec, ASSERT1(ccoef->getLocation() == location); ASSERT1(d->getLocation() == location); - Coordinates *coord = mesh->coordinates(location); + Coordinates *coord = mesh->getCoordinates(location); BOUT_OMP(parallel for) for(int kz = 0; kz <= maxmode; kz++) { @@ -426,7 +426,7 @@ void Laplacian::tridagMatrix(dcomplex *avec, dcomplex *bvec, dcomplex *cvec, int xs = 0; // xstart set to the start of x on this processor (including ghost points) int xe = mesh->LocalNx-1; // xend set to the end of x on this processor (including ghost points) - Coordinates *coord = mesh->coordinates(location); + Coordinates *coord = mesh->getCoordinates(location); // Do not want boundary cells if x is periodic for cyclic solver. Only other solver which // works with periodicX is serial_tri, which uses includeguards==true, so the below isn't called. diff --git a/src/invert/laplacexy/laplacexy.cxx b/src/invert/laplacexy/laplacexy.cxx index 966d78508d..6793880b8d 100644 --- a/src/invert/laplacexy/laplacexy.cxx +++ b/src/invert/laplacexy/laplacexy.cxx @@ -291,7 +291,7 @@ LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) : mesh(m), locat void LaplaceXY::setCoefs(const Field2D &A, const Field2D &B) { Timer timer("invert"); - Coordinates *coords = mesh->coordinates(location); + Coordinates *coords = mesh->getCoordinates(location); ////////////////////////////////////////////////// // Set Matrix elements diff --git a/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx b/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx index 6d98fba3e2..8567b0c740 100644 --- a/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx +++ b/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx @@ -62,7 +62,7 @@ void LaplaceXZcyclic::setCoefs(const Field2D &A2D, const Field2D &B2D) { // Set coefficients - Coordinates *coord = mesh->coordinates(location); + Coordinates *coord = mesh->getCoordinates(location); // NOTE: For now the X-Z terms are omitted, so check that they are small ASSERT2(max(abs(coord->g13)) < 1e-5); diff --git a/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx b/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx index dbe916b7fe..6095919064 100644 --- a/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx +++ b/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx @@ -368,7 +368,7 @@ void LaplaceXZpetsc::setCoefs(const Field3D &Ain, const Field3D &Bin) { // // (1/J) d/dx ( A * J * g11 d/dx ) + (1/J) d/dz ( A * J * g33 d/dz ) + B - Coordinates *coords = mesh->coordinates(location); + Coordinates *coords = mesh->getCoordinates(location); // NOTE: For now the X-Z terms are omitted, so check that they are small ASSERT2(max(abs(coords->g13)) < 1e-5); diff --git a/src/invert/parderiv/impls/cyclic/cyclic.cxx b/src/invert/parderiv/impls/cyclic/cyclic.cxx index bedfb8367d..29d4bc8dde 100644 --- a/src/invert/parderiv/impls/cyclic/cyclic.cxx +++ b/src/invert/parderiv/impls/cyclic/cyclic.cxx @@ -89,7 +89,7 @@ const Field3D InvertParCR::solve(const Field3D &f) { result.allocate(); result.setLocation(f.getLocation()); - Coordinates *coord = mesh->coordinates(f.getLocation()); + Coordinates *coord = mesh->getCoordinates(f.getLocation()); // Create cyclic reduction object CyclicReduce *cr = diff --git a/src/invert/parderiv/impls/serial/serial.cxx b/src/invert/parderiv/impls/serial/serial.cxx index 1ba7b5b36c..7cc0fd128e 100644 --- a/src/invert/parderiv/impls/serial/serial.cxx +++ b/src/invert/parderiv/impls/serial/serial.cxx @@ -67,7 +67,7 @@ const Field3D InvertParSerial::solve(const Field3D &f) { result.allocate(); result.setLocation(f.getLocation()); - Coordinates *coord = mesh->coordinates(f.getLocation()); + Coordinates *coord = mesh->getCoordinates(f.getLocation()); // Loop over flux-surfaces SurfaceIter surf(mesh); diff --git a/src/mesh/boundary_standard.cxx b/src/mesh/boundary_standard.cxx index c82d8f7c0f..c55fef3510 100644 --- a/src/mesh/boundary_standard.cxx +++ b/src/mesh/boundary_standard.cxx @@ -23,88 +23,92 @@ lead to an out of bounds access error later but we add it here to provide a more explanatory message. */ -void verifyNumPoints(BoundaryRegion *region, int ptsRequired) { - TRACE("Verifying number of points available for BC"); +namespace { + void verifyNumPoints(BoundaryRegion *region, int ptsRequired) { + TRACE("Verifying number of points available for BC"); #ifndef CHECK - return; //No checking so just return + return; //No checking so just return #else - int ptsAvailGlobal, ptsAvailLocal, ptsAvail; - string side, gridType; - - //Initialise var in case of no match and CHECK<=2 - ptsAvail = ptsRequired; //Ensures test passes without exception - - switch(region->location) { - case BNDRY_XIN: - case BNDRY_XOUT: { - side = "x"; + Mesh* localmesh = region->localmesh; - //Here 2*mesh->xstart is the total number of guard/boundary cells - ptsAvailGlobal = mesh->GlobalNx - 2*mesh->xstart; + int ptsAvailGlobal, ptsAvailLocal, ptsAvail; + string side, gridType; - //Work out how many processor local points we have excluding boundaries - //but including ghost/guard cells - ptsAvailLocal = mesh->LocalNx; - if(mesh->firstX()) ptsAvailLocal -= mesh->xstart; - if(mesh->lastX()) ptsAvailLocal -= mesh->xstart; + //Initialise var in case of no match and CHECK<=2 + ptsAvail = ptsRequired; //Ensures test passes without exception - //Now decide if it's a local or global limit, prefer global if a tie - if(ptsAvailGlobal <= ptsAvailLocal){ - ptsAvail = ptsAvailGlobal; - gridType = "global"; - }else{ - ptsAvail = ptsAvailLocal; - gridType = "local"; - } + switch(region->location) { + case BNDRY_XIN: + case BNDRY_XOUT: { + side = "x"; - break; - } - case BNDRY_YUP: - case BNDRY_YDOWN: { - side = "y"; + //Here 2*localmesh->xstart is the total number of guard/boundary cells + ptsAvailGlobal = localmesh->GlobalNx - 2*localmesh->xstart; - //Here 2*mesh->ystart is the total number of guard/boundary cells - ptsAvailGlobal = mesh->GlobalNy - 2*mesh->ystart; + //Work out how many processor local points we have excluding boundaries + //but including ghost/guard cells + ptsAvailLocal = localmesh->LocalNx; + if(localmesh->firstX()) ptsAvailLocal -= localmesh->xstart; + if(localmesh->lastX()) ptsAvailLocal -= localmesh->xstart; - //Work out how many processor local points we have excluding boundaries - //but including ghost/guard cells - ptsAvailLocal = mesh->LocalNy; - if(mesh->firstY()) ptsAvailLocal -= mesh->ystart; - if(mesh->lastY()) ptsAvailLocal -= mesh->ystart; + //Now decide if it's a local or global limit, prefer global if a tie + if(ptsAvailGlobal <= ptsAvailLocal){ + ptsAvail = ptsAvailGlobal; + gridType = "global"; + }else{ + ptsAvail = ptsAvailLocal; + gridType = "local"; + } - //Now decide if it's a local or global limit, prefer global if a tie - if(ptsAvailGlobal <= ptsAvailLocal){ - ptsAvail = ptsAvailGlobal; - gridType = "global"; - }else{ - ptsAvail = ptsAvailLocal; - gridType = "local"; + break; } + case BNDRY_YUP: + case BNDRY_YDOWN: { + side = "y"; - break; - } + //Here 2*localmesh->ystart is the total number of guard/boundary cells + ptsAvailGlobal = localmesh->GlobalNy - 2*localmesh->ystart; + + //Work out how many processor local points we have excluding boundaries + //but including ghost/guard cells + ptsAvailLocal = localmesh->LocalNy; + if(localmesh->firstY()) ptsAvailLocal -= localmesh->ystart; + if(localmesh->lastY()) ptsAvailLocal -= localmesh->ystart; + + //Now decide if it's a local or global limit, prefer global if a tie + if(ptsAvailGlobal <= ptsAvailLocal){ + ptsAvail = ptsAvailGlobal; + gridType = "global"; + }else{ + ptsAvail = ptsAvailLocal; + gridType = "local"; + } + + break; + } #if CHECK > 2 //Only fail on Unrecognised boundary for extreme checking - default : { - throw BoutException("Unrecognised boundary region (%s) for verifyNumPoints.",region->location); - } + default : { + throw BoutException("Unrecognised boundary region (%s) for verifyNumPoints.",region->location); + } #endif - } + } - //Now check we have enough points and if not throw an exception - if(ptsAvail < ptsRequired){ - throw BoutException("Too few %s grid points for %s boundary, have %d but need at least %d", - gridType.c_str(),side.c_str(),ptsAvail,ptsRequired); - } + //Now check we have enough points and if not throw an exception + if(ptsAvail < ptsRequired){ + throw BoutException("Too few %s grid points for %s boundary, have %d but need at least %d", + gridType.c_str(),side.c_str(),ptsAvail,ptsRequired); + } #endif + } } /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryDirichlet::clone(BoundaryRegion *region, const list &args){ - verifyNumPoints(region,1); + verifyNumPoints(region, 1); std::shared_ptr newgen; if(!args.empty()) { @@ -121,7 +125,13 @@ void BoundaryDirichlet::apply(Field2D &f){ void BoundaryDirichlet::apply(Field2D &f,BoutReal t) { // Set (at 2nd order) the value at the mid-point between the guard cell and the grid cell to be val // N.B. Only first guard cells (closest to the grid) should ever be used - + + Mesh* localmesh = f.getMesh(); + + // Check for staggered grids + CELL_LOC loc = f.getLocation(); + ASSERT1(localmesh->StaggerGrids || loc == CELL_CENTRE); + bndry->first(); // Decide which generator to use @@ -130,172 +140,163 @@ void BoundaryDirichlet::apply(Field2D &f,BoutReal t) { fg = f.getBndryGenerator(bndry->location); BoutReal val = 0.0; - - // Check for staggered grids - - CELL_LOC loc = f.getLocation(); - if(mesh->StaggerGrids && loc != CELL_CENTRE) { - // Staggered. Need to apply slightly differently - - if( loc == CELL_XLOW ) { - // shifted in X - - if(bndry->bx > 0) { - // Outer x boundary - - for(; !bndry->isDone(); bndry->next1d()) { - if(fg) { - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) - + mesh->GlobalX(bndry->x - bndry->bx) ); - BoutReal ynorm = mesh->GlobalY(bndry->y); - val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); - } - - f(bndry->x,bndry->y) = val; - - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y ; - - f(xi, yi) = 2*f(xi - bndry->bx, yi) - f(xi - 2*bndry->bx, yi); - } - } - } - if(bndry->bx < 0) { - // Inner x boundary. Set one point inwards - for(; !bndry->isDone(); bndry->next1d()) { - if(fg) { - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) - + mesh->GlobalX(bndry->x - bndry->bx) ); - BoutReal ynorm = mesh->GlobalY(bndry->y); - val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); - } - - f(bndry->x - bndry->bx,bndry->y) = val; + if( loc == CELL_XLOW ) { + // shifted in X - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=0;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y ; - - f(xi, yi) = 2*f(xi - bndry->bx, yi) - f(xi - 2*bndry->bx, yi); - } + if(bndry->bx > 0) { + // Outer x boundary + + for(; !bndry->isDone(); bndry->next1d()) { + if(fg) { + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) + + localmesh->GlobalX(bndry->x - bndry->bx) ); + BoutReal ynorm = localmesh->GlobalY(bndry->y); + val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); + } + + f(bndry->x,bndry->y) = val; + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y ; + + f(xi, yi) = 2*f(xi - bndry->bx, yi) - f(xi - 2*bndry->bx, yi); } } - if(bndry->by !=0){ - // y boundaries - for(; !bndry->isDone(); bndry->next1d()) { - if(fg) { - // x norm is shifted by half a grid point because it is staggered. - // y norm is located half way between first grid cell and guard cell. - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) + mesh->GlobalX(bndry->x - 1) ); - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) + mesh->GlobalY(bndry->y - bndry->by) ); - val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); - } - f(bndry->x,bndry->y) = 2*val - f(bndry->x-bndry->bx, bndry->y-bndry->by); - - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=1;iwidth;i++) { - int xi = bndry->x ; - int yi = bndry->y + i*bndry->by; - f(xi, yi) = 2*f(xi, yi - bndry->by) - f(xi, yi - 2*bndry->by); - } + } + if(bndry->bx < 0) { + // Inner x boundary. Set one point inwards + for(; !bndry->isDone(); bndry->next1d()) { + if(fg) { + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) + + localmesh->GlobalX(bndry->x - bndry->bx) ); + BoutReal ynorm = localmesh->GlobalY(bndry->y); + val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); + } + + f(bndry->x - bndry->bx,bndry->y) = val; + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=0;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y ; + + f(xi, yi) = 2*f(xi - bndry->bx, yi) - f(xi - 2*bndry->bx, yi); } } } - else if( loc == CELL_YLOW ) { - // Y boundary, and field is shifted in Y - - if(bndry->by > 0) { - // Upper y boundary - - for(; !bndry->isDone(); bndry->next1d()) { - if(fg) { - BoutReal xnorm = mesh->GlobalX(bndry->x); - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) - + mesh->GlobalY(bndry->y - bndry->by) ); - val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); - } - - f(bndry->x,bndry->y) = val; - - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=1;iwidth;i++) { - int xi = bndry->x ; - int yi = bndry->y + i*bndry->by; - f(xi, yi) = 2*f(xi, yi - bndry->by) - f(xi, yi - 2*bndry->by); - } + if(bndry->by !=0){ + // y boundaries + for(; !bndry->isDone(); bndry->next1d()) { + if(fg) { + // x norm is shifted by half a grid point because it is staggered. + // y norm is located half way between first grid cell and guard cell. + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) + localmesh->GlobalX(bndry->x - 1) ); + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) + localmesh->GlobalY(bndry->y - bndry->by) ); + val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); + } + f(bndry->x,bndry->y) = 2*val - f(bndry->x-bndry->bx, bndry->y-bndry->by); + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=1;iwidth;i++) { + int xi = bndry->x ; + int yi = bndry->y + i*bndry->by; + f(xi, yi) = 2*f(xi, yi - bndry->by) - f(xi, yi - 2*bndry->by); } } - if(bndry->by < 0) { - // Lower y boundary. Set one point inwards - for(; !bndry->isDone(); bndry->next1d()) { - if(fg) { - BoutReal xnorm = mesh->GlobalX(bndry->x); - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) - + mesh->GlobalY(bndry->y - bndry->by) ); - - val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); - } - - f(bndry->x,bndry->y - bndry->by) = val; + } + } else if( loc == CELL_YLOW ) { + // Y boundary, and field is shifted in Y + + if(bndry->by > 0) { + // Upper y boundary + + for(; !bndry->isDone(); bndry->next1d()) { + if(fg) { + BoutReal xnorm = localmesh->GlobalX(bndry->x); + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) + + localmesh->GlobalY(bndry->y - bndry->by) ); + val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); + } - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=0;iwidth;i++) { - int xi = bndry->x ; - int yi = bndry->y + i*bndry->by; - f(xi, yi) = 2*f(xi, yi - bndry->by) - f(xi, yi - 2*bndry->by); - } + f(bndry->x,bndry->y) = val; + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=1;iwidth;i++) { + int xi = bndry->x ; + int yi = bndry->y + i*bndry->by; + f(xi, yi) = 2*f(xi, yi - bndry->by) - f(xi, yi - 2*bndry->by); } } - if (bndry->bx !=0){ - // x boundaries - for(; !bndry->isDone(); bndry->next1d()) { - - if(fg) { - // x norm is located half way between first grid cell and guard cell. - // y norm is shifted by half a grid point because it is staggered. - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) + mesh->GlobalX(bndry->x - bndry->bx) ); - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) + mesh->GlobalY(bndry->y - 1) ); - val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); - } - f(bndry->x,bndry->y) = 2*val - f(bndry->x-bndry->bx, bndry->y-bndry->by); - - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y ; - f(xi, yi) = 2*f(xi - bndry->bx, yi) - f(xi - 2*bndry->bx, yi); - } + } + if(bndry->by < 0) { + // Lower y boundary. Set one point inwards + for(; !bndry->isDone(); bndry->next1d()) { + if(fg) { + BoutReal xnorm = localmesh->GlobalX(bndry->x); + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) + + localmesh->GlobalY(bndry->y - bndry->by) ); + + val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); + } + + f(bndry->x,bndry->y - bndry->by) = val; + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=0;iwidth;i++) { + int xi = bndry->x ; + int yi = bndry->y + i*bndry->by; + f(xi, yi) = 2*f(xi, yi - bndry->by) - f(xi, yi - 2*bndry->by); + } + } + } + if (bndry->bx !=0){ + // x boundaries + for(; !bndry->isDone(); bndry->next1d()) { + + if(fg) { + // x norm is located half way between first grid cell and guard cell. + // y norm is shifted by half a grid point because it is staggered. + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) + localmesh->GlobalX(bndry->x - bndry->bx) ); + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) + localmesh->GlobalY(bndry->y - 1) ); + val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); + } + f(bndry->x,bndry->y) = 2*val - f(bndry->x-bndry->bx, bndry->y-bndry->by); + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y ; + f(xi, yi) = 2*f(xi - bndry->bx, yi) - f(xi - 2*bndry->bx, yi); } } } } else { - // Non-staggered, standard case - + // CELL_CENTRE or CELL_ZLOW + for(; !bndry->isDone(); bndry->next1d()) { - + if(fg) { - // Calculate the X and Y normalised values half-way between the guard cell and grid cell - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) // In the guard cell - + mesh->GlobalX(bndry->x - bndry->bx) ); // the grid cell - - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) // In the guard cell - + mesh->GlobalY(bndry->y - bndry->by) ); // the grid cell - - val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); + // Calculate the X and Y normalised values half-way between the guard cell and grid cell + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) // In the guard cell + + localmesh->GlobalX(bndry->x - bndry->bx) ); // the grid cell + + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) // In the guard cell + + localmesh->GlobalY(bndry->y - bndry->by) ); // the grid cell + + val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); } - + f(bndry->x,bndry->y) = 2*val - f(bndry->x-bndry->bx, bndry->y-bndry->by); - + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives for(int i=1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->bx; - f(xi, yi) = 2*f(xi - bndry->bx, yi - bndry->by) - f(xi - 2*bndry->bx, yi - 2*bndry->by); - } + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->bx; + f(xi, yi) = 2*f(xi - bndry->bx, yi - bndry->by) - f(xi - 2*bndry->bx, yi - 2*bndry->by); + } } } } @@ -309,6 +310,12 @@ void BoundaryDirichlet::apply(Field3D &f,BoutReal t) { // Set (at 2nd order) the value at the mid-point between the guard cell and the grid cell to be val // N.B. Only first guard cells (closest to the grid) should ever be used + Mesh* localmesh = f.getMesh(); + + // Check for staggered grids + CELL_LOC loc = f.getLocation(); + ASSERT1(localmesh->StaggerGrids || loc == CELL_CENTRE); + bndry->first(); // Decide which generator to use @@ -318,178 +325,169 @@ void BoundaryDirichlet::apply(Field3D &f,BoutReal t) { BoutReal val = 0.0; - // Check for staggered grids - - CELL_LOC loc = f.getLocation(); - if(mesh->StaggerGrids && loc != CELL_CENTRE) { - // Staggered. Need to apply slightly differently - - if( loc == CELL_XLOW ) { - // X boundary, and field is shifted in X - - if(bndry->bx > 0) { - // Outer x boundary - - for(; !bndry->isDone(); bndry->next1d()) { - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) - + mesh->GlobalX(bndry->x - bndry->bx) ); - BoutReal ynorm = mesh->GlobalY(bndry->y); - - for(int zk=0;zkLocalNz;zk++) { - if(fg){ - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(mesh->LocalNz), t); - } - f(bndry->x,bndry->y, zk) = val; - - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y ; - - f(xi, yi, zk) = 2*f(xi - bndry->bx, yi , zk) - f(xi- 2*bndry->bx, yi , zk); - } - } - } + if( loc == CELL_XLOW ) { + // X boundary, and field is shifted in X + + if(bndry->bx > 0) { + // Outer x boundary + + for(; !bndry->isDone(); bndry->next1d()) { + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) + + localmesh->GlobalX(bndry->x - bndry->bx) ); + BoutReal ynorm = localmesh->GlobalY(bndry->y); + + for(int zk=0;zkLocalNz;zk++) { + if(fg){ + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(localmesh->LocalNz), t); + } + f(bndry->x,bndry->y, zk) = val; + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y ; + + f(xi, yi, zk) = 2*f(xi - bndry->bx, yi , zk) - f(xi- 2*bndry->bx, yi , zk); + } + } } - if (bndry->bx < 0){ - // Inner x boundary. Set one point inwards - for(; !bndry->isDone(); bndry->next1d()) { - - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) - + mesh->GlobalX(bndry->x - bndry->bx) ); - BoutReal ynorm = mesh->GlobalY(bndry->y); - - for(int zk=0;zkLocalNz;zk++) { - if(fg){ - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(mesh->LocalNz), t); - } - f(bndry->x - bndry->bx,bndry->y, zk) = val; - f(bndry->x,bndry->y, zk) = f(bndry->x - bndry->bx,bndry->y, zk); - - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=0;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y ; - - f(xi, yi, zk) = 2*f(xi - bndry->bx, yi , zk) - f(xi- 2*bndry->bx, yi , zk); - } - } - } + } + if (bndry->bx < 0){ + // Inner x boundary. Set one point inwards + for(; !bndry->isDone(); bndry->next1d()) { + + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) + + localmesh->GlobalX(bndry->x - bndry->bx) ); + BoutReal ynorm = localmesh->GlobalY(bndry->y); + + for(int zk=0;zkLocalNz;zk++) { + if(fg){ + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(localmesh->LocalNz), t); + } + f(bndry->x - bndry->bx,bndry->y, zk) = val; + f(bndry->x,bndry->y, zk) = f(bndry->x - bndry->bx,bndry->y, zk); + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=0;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y ; + + f(xi, yi, zk) = 2*f(xi - bndry->bx, yi , zk) - f(xi- 2*bndry->bx, yi , zk); + } + } } - if(bndry->by !=0){ - // y boundaries - for(; !bndry->isDone(); bndry->next1d()) { - // x norm is shifted by half a grid point because it is staggered. - // y norm is located half way between first grid cell and guard cell. - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) + mesh->GlobalX(bndry->x - 1) ); - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) + mesh->GlobalY(bndry->y - bndry->by) ); - - for(int zk=0;zkLocalNz;zk++) { - if(fg){ - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(mesh->LocalNz), t); - } - f(bndry->x,bndry->y,zk) = 2*val - f(bndry->x-bndry->bx, bndry->y-bndry->by, zk); - - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=1;iwidth;i++) { - int xi = bndry->x ; - int yi = bndry->y + i*bndry->by; - - f(xi, yi, zk) = 2*f(xi, yi - bndry->by, zk) - f(xi, yi - 2*bndry->by, zk); - } - } - } - } - } - else if( loc == CELL_YLOW ) { - // Shifted in Y - - if(bndry->by > 0) { - // Upper y boundary boundary - - for(; !bndry->isDone(); bndry->next1d()) { - BoutReal xnorm = mesh->GlobalX(bndry->x); - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) + mesh->GlobalY(bndry->y - bndry->by) ); - for(int zk=0;zkLocalNz;zk++) { - if(fg){ - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(mesh->LocalNz), t); - } - f(bndry->x,bndry->y,zk) = val; - - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=1;iwidth;i++) { - int xi = bndry->x ; - int yi = bndry->y + i*bndry->by; - - f(xi, yi, zk) = 2.0*f(xi, yi - bndry->by, zk) - f(xi, yi - 2*bndry->by, zk); - } - } - } + } + if(bndry->by !=0){ + // y boundaries + for(; !bndry->isDone(); bndry->next1d()) { + // x norm is shifted by half a grid point because it is staggered. + // y norm is located half way between first grid cell and guard cell. + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) + localmesh->GlobalX(bndry->x - 1) ); + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) + localmesh->GlobalY(bndry->y - bndry->by) ); + + for(int zk=0;zkLocalNz;zk++) { + if(fg){ + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(localmesh->LocalNz), t); + } + f(bndry->x,bndry->y,zk) = 2*val - f(bndry->x-bndry->bx, bndry->y-bndry->by, zk); + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=1;iwidth;i++) { + int xi = bndry->x ; + int yi = bndry->y + i*bndry->by; + + f(xi, yi, zk) = 2*f(xi, yi - bndry->by, zk) - f(xi, yi - 2*bndry->by, zk); + } + } } - if(bndry->by < 0){ - // Lower y boundary. Set one point inwards - for(; !bndry->isDone(); bndry->next1d()) { - - BoutReal xnorm = mesh->GlobalX(bndry->x); - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) + mesh->GlobalY(bndry->y - bndry->by) ); - - for(int zk=0;zkLocalNz;zk++) { - if(fg){ - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(mesh->LocalNz), t); - } - f(bndry->x,bndry->y - bndry->by, zk) = val; - - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=0;iwidth;i++) { - int xi = bndry->x ; - int yi = bndry->y + i*bndry->by; - - f(xi, yi, zk) = 2*f(xi, yi - bndry->by, zk) - f(xi, yi - 2*bndry->by, zk); - } - } - } + } + } else if( loc == CELL_YLOW ) { + // Shifted in Y + + if(bndry->by > 0) { + // Upper y boundary boundary + + for(; !bndry->isDone(); bndry->next1d()) { + BoutReal xnorm = localmesh->GlobalX(bndry->x); + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) + localmesh->GlobalY(bndry->y - bndry->by) ); + for(int zk=0;zkLocalNz;zk++) { + if(fg){ + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(localmesh->LocalNz), t); + } + f(bndry->x,bndry->y,zk) = val; + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=1;iwidth;i++) { + int xi = bndry->x ; + int yi = bndry->y + i*bndry->by; + + f(xi, yi, zk) = 2.0*f(xi, yi - bndry->by, zk) - f(xi, yi - 2*bndry->by, zk); + } + } } - if(bndry->bx != 0){ - // x boundaries - for(; !bndry->isDone(); bndry->next1d()) { - // x norm is located half way between first grid cell and guard cell. - // y norm is shifted by half a grid point because it is staggered. - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) + mesh->GlobalX(bndry->x - bndry->bx) ); - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) + mesh->GlobalY(bndry->y - 1) ); - - for(int zk=0;zkLocalNz;zk++) { - if(fg) - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(mesh->LocalNz), t); - - f(bndry->x,bndry->y,zk) = 2*val - f(bndry->x-bndry->bx, bndry->y-bndry->by, zk); - - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y ; - - f(xi, yi, zk) = 2*f(xi - bndry->bx, yi , zk) - f(xi - 2*bndry->bx, yi, zk); - } - } - } - } - } - } - else { - // Standard (non-staggered) case + } + if(bndry->by < 0){ + // Lower y boundary. Set one point inwards + for(; !bndry->isDone(); bndry->next1d()) { + + BoutReal xnorm = localmesh->GlobalX(bndry->x); + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) + localmesh->GlobalY(bndry->y - bndry->by) ); + + for(int zk=0;zkLocalNz;zk++) { + if(fg){ + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(localmesh->LocalNz), t); + } + f(bndry->x,bndry->y - bndry->by, zk) = val; + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=0;iwidth;i++) { + int xi = bndry->x ; + int yi = bndry->y + i*bndry->by; + + f(xi, yi, zk) = 2*f(xi, yi - bndry->by, zk) - f(xi, yi - 2*bndry->by, zk); + } + } + } + } + if(bndry->bx != 0){ + // x boundaries + for(; !bndry->isDone(); bndry->next1d()) { + // x norm is located half way between first grid cell and guard cell. + // y norm is shifted by half a grid point because it is staggered. + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) + localmesh->GlobalX(bndry->x - bndry->bx) ); + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) + localmesh->GlobalY(bndry->y - 1) ); + + for(int zk=0;zkLocalNz;zk++) { + if(fg) + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(localmesh->LocalNz), t); + + f(bndry->x,bndry->y,zk) = 2*val - f(bndry->x-bndry->bx, bndry->y-bndry->by, zk); + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y ; + + f(xi, yi, zk) = 2*f(xi - bndry->bx, yi , zk) - f(xi - 2*bndry->bx, yi, zk); + } + } + } + } + } else { + // CELL_CENTRE or CELL_ZLOW for(; !bndry->isDone(); bndry->next1d()) { // Calculate the X and Y normalised values half-way between the guard cell and grid cell - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) // In the guard cell - + mesh->GlobalX(bndry->x - bndry->bx) ); // the grid cell + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) // In the guard cell + + localmesh->GlobalX(bndry->x - bndry->bx) ); // the grid cell - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) // In the guard cell - + mesh->GlobalY(bndry->y - bndry->by) ); // the grid cell - - for(int zk=0;zkLocalNz;zk++) { - if(fg){ - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(mesh->LocalNz), t); - } - f(bndry->x,bndry->y,zk) = 2*val - f(bndry->x-bndry->bx, bndry->y-bndry->by, zk); + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) // In the guard cell + + localmesh->GlobalY(bndry->y - bndry->by) ); // the grid cell + + for(int zk=0;zkLocalNz;zk++) { + if(fg){ + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(localmesh->LocalNz), t); + } + f(bndry->x,bndry->y,zk) = 2*val - f(bndry->x-bndry->bx, bndry->y-bndry->by, zk); // We've set the first boundary point using extrapolation in // the line above. The below block of code is attempting to @@ -525,11 +523,11 @@ void BoundaryDirichlet::apply(Field3D &f,BoutReal t) { // Set any other guard cells using the values on the cells int xi = bndry->x + i*bndry->bx; int yi = bndry->y + i*bndry->by; - xnorm = mesh->GlobalX(xi); - ynorm = mesh->GlobalY(yi); - for(int zk=0;zkLocalNz;zk++) { + xnorm = localmesh->GlobalX(xi); + ynorm = localmesh->GlobalY(yi); + for(int zk=0;zkLocalNz;zk++) { if(fg) { - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(mesh->LocalNz), t); + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(localmesh->LocalNz), t); } f(xi, yi, zk) = val; } @@ -546,9 +544,10 @@ void BoundaryDirichlet::apply_ddt(Field2D &f) { } void BoundaryDirichlet::apply_ddt(Field3D &f) { + Mesh* localmesh = f.getMesh(); Field3D *dt = f.timeDeriv(); for(bndry->first(); !bndry->isDone(); bndry->next()) - for(int z=0;zLocalNz;z++) + for(int z=0;zLocalNz;z++) (*dt)(bndry->x,bndry->y,z) = 0.; // Set time derivative to zero } @@ -557,7 +556,7 @@ void BoundaryDirichlet::apply_ddt(Field3D &f) { // New implementation, accurate to higher order BoundaryOp* BoundaryDirichlet_O3::clone(BoundaryRegion *region, const list &args){ - verifyNumPoints(region,2); + verifyNumPoints(region, 2); std::shared_ptr newgen = nullptr; if(!args.empty()) { // First argument should be an expression @@ -573,7 +572,13 @@ void BoundaryDirichlet_O3::apply(Field2D &f){ void BoundaryDirichlet_O3::apply(Field2D &f,BoutReal t) { // Set (at 2nd order) the value at the mid-point between the guard cell and the grid cell to be val // N.B. Only first guard cells (closest to the grid) should ever be used - + + Mesh* localmesh = f.getMesh(); + + // Check for staggered grids + CELL_LOC loc = f.getLocation(); + ASSERT1(localmesh->StaggerGrids || loc == CELL_CENTRE); + bndry->first(); // Decide which generator to use @@ -582,169 +587,158 @@ void BoundaryDirichlet_O3::apply(Field2D &f,BoutReal t) { fg = f.getBndryGenerator(bndry->location); BoutReal val = 0.0; - - // Check for staggered grids - - CELL_LOC loc = f.getLocation(); - if(mesh->StaggerGrids && loc != CELL_CENTRE) { - // Staggered. Need to apply slightly differently - - if( loc == CELL_XLOW) { - // Field is shifted in X - - if(bndry->bx > 0) { - // Outer x boundary - for(; !bndry->isDone(); bndry->next1d()) { - if(fg) { - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) + mesh->GlobalX(bndry->x - bndry->bx) ); - BoutReal ynorm = mesh->GlobalY(bndry->y); - val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); - } - - f(bndry->x,bndry->y) = val; - - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); - } - } + if( loc == CELL_XLOW) { + // Field is shifted in X + + if(bndry->bx > 0) { + // Outer x boundary + for(; !bndry->isDone(); bndry->next1d()) { + if(fg) { + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) + localmesh->GlobalX(bndry->x - bndry->bx) ); + BoutReal ynorm = localmesh->GlobalY(bndry->y); + val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); + } + + f(bndry->x,bndry->y) = val; + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); + } } - if(bndry->bx < 0) { - // Inner x boundary. Set one point inwards - for(; !bndry->isDone(); bndry->next1d()) { - if(fg) { - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) + mesh->GlobalX(bndry->x - bndry->bx) ); - BoutReal ynorm = mesh->GlobalY(bndry->y); - val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); - } - f(bndry->x - bndry->bx,bndry->y) = val; - - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=0;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); - } - } + } + if(bndry->bx < 0) { + // Inner x boundary. Set one point inwards + for(; !bndry->isDone(); bndry->next1d()) { + if(fg) { + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) + localmesh->GlobalX(bndry->x - bndry->bx) ); + BoutReal ynorm = localmesh->GlobalY(bndry->y); + val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); + } + f(bndry->x - bndry->bx,bndry->y) = val; + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=0;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); + } } - if(bndry->by != 0){ - for(; !bndry->isDone(); bndry->next1d()) { - if(fg) { - // x norm is shifted by half a grid point because it is staggered. - // y norm is located half way between first grid cell and guard cell. - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) + mesh->GlobalX(bndry->x - 1) ); - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) + mesh->GlobalY(bndry->y - bndry->by) ); - - val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); - } - - f(bndry->x,bndry->y) = (8./3)*val - 2.*f(bndry->x-bndry->bx, bndry->y-bndry->by) + f(bndry->x-2*bndry->bx, bndry->y-2*bndry->by)/3.; - - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); - } - - } + } + if(bndry->by != 0){ + for(; !bndry->isDone(); bndry->next1d()) { + if(fg) { + // x norm is shifted by half a grid point because it is staggered. + // y norm is located half way between first grid cell and guard cell. + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) + localmesh->GlobalX(bndry->x - 1) ); + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) + localmesh->GlobalY(bndry->y - bndry->by) ); + + val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); + } + + f(bndry->x,bndry->y) = (8./3)*val - 2.*f(bndry->x-bndry->bx, bndry->y-bndry->by) + f(bndry->x-2*bndry->bx, bndry->y-2*bndry->by)/3.; + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); + } + } } - else if( loc == CELL_YLOW ) { - // Field is shifted in Y - - if(bndry->by > 0) { - // Upper y boundary - - for(; !bndry->isDone(); bndry->next1d()) { - if(fg) { - BoutReal xnorm = mesh->GlobalX(bndry->x); - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) + mesh->GlobalY(bndry->y - bndry->by) ); - val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); - } - - f(bndry->x,bndry->y) = val; - - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); - } - - } + } else if( loc == CELL_YLOW ) { + // Field is shifted in Y + + if(bndry->by > 0) { + // Upper y boundary + + for(; !bndry->isDone(); bndry->next1d()) { + if(fg) { + BoutReal xnorm = localmesh->GlobalX(bndry->x); + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) + localmesh->GlobalY(bndry->y - bndry->by) ); + val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); + } + + f(bndry->x,bndry->y) = val; + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); + } + } - if(bndry->by < 0) { - // Lower y boundary. Set one point inwards - for(; !bndry->isDone(); bndry->next1d()) { - if(fg) { - BoutReal xnorm = mesh->GlobalX(bndry->x); - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) + mesh->GlobalY(bndry->y - bndry->by) ); - val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); - } - - f(bndry->x,bndry->y - bndry->by) = val; - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=0;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); - } + } + if(bndry->by < 0) { + // Lower y boundary. Set one point inwards + for(; !bndry->isDone(); bndry->next1d()) { + if(fg) { + BoutReal xnorm = localmesh->GlobalX(bndry->x); + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) + localmesh->GlobalY(bndry->y - bndry->by) ); + val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); + } + + f(bndry->x,bndry->y - bndry->by) = val; + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=0;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); + } - } } - if(bndry->bx != 0){ - // x boundaries - for(; !bndry->isDone(); bndry->next1d()) { - - if(fg) { - // x norm is located half way between first grid cell and guard cell. - // y norm is shifted by half a grid point because it is staggered. - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) + mesh->GlobalX(bndry->x - bndry->bx) ); - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) + mesh->GlobalY(bndry->y - 1) ); - - val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); - } - - f(bndry->x,bndry->y) = (8./3)*val - 2.*f(bndry->x-bndry->bx, bndry->y-bndry->by) + f(bndry->x-2*bndry->bx, bndry->y-2*bndry->by)/3.; - - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); - } - } + } + if(bndry->bx != 0){ + // x boundaries + for(; !bndry->isDone(); bndry->next1d()) { + + if(fg) { + // x norm is located half way between first grid cell and guard cell. + // y norm is shifted by half a grid point because it is staggered. + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) + localmesh->GlobalX(bndry->x - bndry->bx) ); + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) + localmesh->GlobalY(bndry->y - 1) ); + + val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); + } + + f(bndry->x,bndry->y) = (8./3)*val - 2.*f(bndry->x-bndry->bx, bndry->y-bndry->by) + f(bndry->x-2*bndry->bx, bndry->y-2*bndry->by)/3.; + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); + } } } - } - else { - // Non-staggered, standard case - + } else { + // CELL_CENTRE or CELL_ZLOW for(; !bndry->isDone(); bndry->next1d()) { - + if(fg) { - // Calculate the X and Y normalised values half-way between the guard cell and grid cell - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) // In the guard cell - + mesh->GlobalX(bndry->x - bndry->bx) ); // the grid cell - - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) // In the guard cell - + mesh->GlobalY(bndry->y - bndry->by) ); // the grid cell - - val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); + // Calculate the X and Y normalised values half-way between the guard cell and grid cell + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) // In the guard cell + + localmesh->GlobalX(bndry->x - bndry->bx) ); // the grid cell + + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) // In the guard cell + + localmesh->GlobalY(bndry->y - bndry->by) ); // the grid cell + + val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); } - + f(bndry->x,bndry->y) = (8./3)*val - 2.*f(bndry->x-bndry->bx, bndry->y-bndry->by) + f(bndry->x-2*bndry->bx, bndry->y-2*bndry->by)/3.; // Need to set second guard cell, as may be used for interpolation or upwinding derivatives for(int i=1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); - } + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); + } } } } @@ -759,6 +753,12 @@ void BoundaryDirichlet_O3::apply(Field3D &f,BoutReal t) { // Set (at 2nd order) the value at the mid-point between the guard cell and the grid cell to be val // N.B. Only first guard cells (closest to the grid) should ever be used + Mesh* localmesh = f.getMesh(); + + // Check for staggered grids + CELL_LOC loc = f.getLocation(); + ASSERT1(localmesh->StaggerGrids || loc == CELL_CENTRE); + bndry->first(); // Decide which generator to use @@ -768,184 +768,175 @@ void BoundaryDirichlet_O3::apply(Field3D &f,BoutReal t) { BoutReal val = 0.0; - // Check for staggered grids - - CELL_LOC loc = f.getLocation(); - if(mesh->StaggerGrids && loc != CELL_CENTRE) { - // Staggered. Need to apply slightly differently - - if( loc == CELL_XLOW ) { - // Field is shifted in X - - if(bndry->bx > 0) { - // Outer x boundary - - for(; !bndry->isDone(); bndry->next1d()) { - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) + mesh->GlobalX(bndry->x - bndry->bx) ); - BoutReal ynorm = mesh->GlobalY(bndry->y); - - for(int zk=0;zkLocalNz;zk++) { - if(fg){ - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(mesh->LocalNz), t); - } - f(bndry->x,bndry->y, zk) = val; - - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) - + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); - } - } - } + if( loc == CELL_XLOW ) { + // Field is shifted in X + + if(bndry->bx > 0) { + // Outer x boundary + + for(; !bndry->isDone(); bndry->next1d()) { + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) + localmesh->GlobalX(bndry->x - bndry->bx) ); + BoutReal ynorm = localmesh->GlobalY(bndry->y); + + for(int zk=0;zkLocalNz;zk++) { + if(fg){ + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(localmesh->LocalNz), t); + } + f(bndry->x,bndry->y, zk) = val; + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) + + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); + } + } } - if(bndry->bx < 0) { - // Inner x boundary. Set one point inwards - for(; !bndry->isDone(); bndry->next1d()) { - - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) + mesh->GlobalX(bndry->x - bndry->bx) ); - BoutReal ynorm = mesh->GlobalY(bndry->y); - - for(int zk=0;zkLocalNz;zk++) { - if(fg){ - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(mesh->LocalNz), t); - } - f(bndry->x - bndry->bx,bndry->y, zk) = val; - - // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives - for(int i=0;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) - + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); - } - } - } + } + if(bndry->bx < 0) { + // Inner x boundary. Set one point inwards + for(; !bndry->isDone(); bndry->next1d()) { + + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) + localmesh->GlobalX(bndry->x - bndry->bx) ); + BoutReal ynorm = localmesh->GlobalY(bndry->y); + + for(int zk=0;zkLocalNz;zk++) { + if(fg){ + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(localmesh->LocalNz), t); + } + f(bndry->x - bndry->bx,bndry->y, zk) = val; + + // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives + for(int i=0;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) + + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); + } + } } - if(bndry->by != 0){ - //y boundaries - - for(; !bndry->isDone(); bndry->next1d()) { - // x norm is shifted by half a grid point because it is staggered. - // y norm is located half way between first grid cell and guard cell. - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) + mesh->GlobalX(bndry->x - 1) ); - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) + mesh->GlobalY(bndry->y - bndry->by) ); - - for(int zk=0;zkLocalNz;zk++) { - if(fg) - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(mesh->LocalNz), t); - - f(bndry->x,bndry->y,zk) = (8./3)*val - 2.*f(bndry->x-bndry->bx, bndry->y-bndry->by,zk) + f(bndry->x-2*bndry->bx, bndry->y-2*bndry->by,zk)/3.; - - // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives - for(int i=1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) - + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); - } - } - } + } + if(bndry->by != 0){ + //y boundaries + + for(; !bndry->isDone(); bndry->next1d()) { + // x norm is shifted by half a grid point because it is staggered. + // y norm is located half way between first grid cell and guard cell. + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) + localmesh->GlobalX(bndry->x - 1) ); + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) + localmesh->GlobalY(bndry->y - bndry->by) ); + + for(int zk=0;zkLocalNz;zk++) { + if(fg) + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(localmesh->LocalNz), t); + + f(bndry->x,bndry->y,zk) = (8./3)*val - 2.*f(bndry->x-bndry->bx, bndry->y-bndry->by,zk) + f(bndry->x-2*bndry->bx, bndry->y-2*bndry->by,zk)/3.; + + // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives + for(int i=1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) + + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); + } + } } } - else if( loc == CELL_YLOW ) { - // Field is shifted in Y - - if(bndry->by > 0) { - // Upper y boundary - - for(; !bndry->isDone(); bndry->next1d()) { - BoutReal xnorm = mesh->GlobalX(bndry->x); - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) + mesh->GlobalY(bndry->y - bndry->by) ); - for(int zk=0;zkLocalNz;zk++) { - if(fg){ - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(mesh->LocalNz), t); - } - f(bndry->x,bndry->y,zk) = val; - - // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives - for(int i=1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) - + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); - } - } - } + } else if( loc == CELL_YLOW ) { + // Field is shifted in Y + + if(bndry->by > 0) { + // Upper y boundary + + for(; !bndry->isDone(); bndry->next1d()) { + BoutReal xnorm = localmesh->GlobalX(bndry->x); + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) + localmesh->GlobalY(bndry->y - bndry->by) ); + for(int zk=0;zkLocalNz;zk++) { + if(fg){ + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(localmesh->LocalNz), t); + } + f(bndry->x,bndry->y,zk) = val; + + // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives + for(int i=1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) + + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); + } + } } - if(bndry->by < 0) { - // Lower y boundary. Set one point inwards - for(; !bndry->isDone(); bndry->next1d()) { - - BoutReal xnorm = mesh->GlobalX(bndry->x); - BoutReal ynorm = 0.5*(mesh->GlobalY(bndry->y)+ mesh->GlobalY(bndry->y - bndry->by) ); - - for(int zk=0;zkLocalNz;zk++) { - if(fg){ - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(mesh->LocalNz), t); - } - f(bndry->x,bndry->y - bndry->by, zk) = val; - - // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives - for(int i=0;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) - + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); - } - } - } + } + if(bndry->by < 0) { + // Lower y boundary. Set one point inwards + for(; !bndry->isDone(); bndry->next1d()) { + + BoutReal xnorm = localmesh->GlobalX(bndry->x); + BoutReal ynorm = 0.5*(localmesh->GlobalY(bndry->y)+ localmesh->GlobalY(bndry->y - bndry->by) ); + + for(int zk=0;zkLocalNz;zk++) { + if(fg){ + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(localmesh->LocalNz), t); + } + f(bndry->x,bndry->y - bndry->by, zk) = val; + + // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives + for(int i=0;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) + + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); + } + } } - if(bndry->bx != 0){ - // x boundaries - for(; !bndry->isDone(); bndry->next1d()) { - // x norm is located half way between first grid cell and guard cell. - // y norm is shifted by half a grid point because it is staggered. - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) + mesh->GlobalX(bndry->x - bndry->bx) ); - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) + mesh->GlobalY(bndry->y - 1) ); - - for(int zk=0;zkLocalNz;zk++) { - if(fg) - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(mesh->LocalNz), t); - - f(bndry->x,bndry->y,zk) = (8./3)*val - 2.*f(bndry->x-bndry->bx, bndry->y-bndry->by,zk) + f(bndry->x-2*bndry->bx, bndry->y-2*bndry->by,zk)/3.; - - // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives - for(int i=1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) - + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); - } - } - } + } + if(bndry->bx != 0){ + // x boundaries + for(; !bndry->isDone(); bndry->next1d()) { + // x norm is located half way between first grid cell and guard cell. + // y norm is shifted by half a grid point because it is staggered. + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) + localmesh->GlobalX(bndry->x - bndry->bx) ); + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) + localmesh->GlobalY(bndry->y - 1) ); + + for(int zk=0;zkLocalNz;zk++) { + if(fg) + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(localmesh->LocalNz), t); + + f(bndry->x,bndry->y,zk) = (8./3)*val - 2.*f(bndry->x-bndry->bx, bndry->y-bndry->by,zk) + f(bndry->x-2*bndry->bx, bndry->y-2*bndry->by,zk)/3.; + + // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives + for(int i=1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) + + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); + } + } } } - } - else { - // Standard (non-staggered) case + } else { + // CELL_CENTRE or CELL_ZLOW for(; !bndry->isDone(); bndry->next1d()) { - // Calculate the X and Y normalised values half-way between the guard cell and grid cell - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) // In the guard cell - + mesh->GlobalX(bndry->x - bndry->bx) ); // the grid cell + // Calculate the X and Y normalised values half-way between the guard cell and grid cell + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) // In the guard cell + + localmesh->GlobalX(bndry->x - bndry->bx) ); // the grid cell - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) // In the guard cell - + mesh->GlobalY(bndry->y - bndry->by) ); // the grid cell - - for(int zk=0;zkLocalNz;zk++) { - if(fg) - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(mesh->LocalNz), t); - - f(bndry->x,bndry->y,zk) = (8./3)*val - 2.*f(bndry->x-bndry->bx, bndry->y-bndry->by,zk) + f(bndry->x-2*bndry->bx, bndry->y-2*bndry->by,zk)/3.; - - // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives - for(int i=1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) - + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); - } + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) // In the guard cell + + localmesh->GlobalY(bndry->y - bndry->by) ); // the grid cell + + for(int zk=0;zkLocalNz;zk++) { + if(fg) + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(localmesh->LocalNz), t); + + f(bndry->x,bndry->y,zk) = (8./3)*val - 2.*f(bndry->x-bndry->bx, bndry->y-bndry->by,zk) + f(bndry->x-2*bndry->bx, bndry->y-2*bndry->by,zk)/3.; + + // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives + for(int i=1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) + + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); + } } } } @@ -958,11 +949,11 @@ void BoundaryDirichlet_O3::apply_ddt(Field2D &f) { } void BoundaryDirichlet_O3::apply_ddt(Field3D &f) { + Mesh* localmesh = f.getMesh(); Field3D *dt = f.timeDeriv(); - bndry->first() ; for(bndry->first(); !bndry->isDone(); bndry->next()){ - for(int z=0;zLocalNz;z++){ + for(int z=0;zLocalNz;z++){ (*dt)(bndry->x,bndry->y,z) = 0.; // Set time derivative to zero } } @@ -972,7 +963,7 @@ void BoundaryDirichlet_O3::apply_ddt(Field3D &f) { // Extrapolate to calculate boundary cell to 4th-order BoundaryOp* BoundaryDirichlet_O4::clone(BoundaryRegion *region, const list &args){ - verifyNumPoints(region,3); + verifyNumPoints(region, 3); std::shared_ptr newgen = nullptr; if(!args.empty()) { // First argument should be an expression @@ -988,7 +979,13 @@ void BoundaryDirichlet_O4::apply(Field2D &f){ void BoundaryDirichlet_O4::apply(Field2D &f,BoutReal t) { // Set (at 2nd order) the value at the mid-point between the guard cell and the grid cell to be val // N.B. Only first guard cells (closest to the grid) should ever be used - + + Mesh* localmesh = f.getMesh(); + + // Check for staggered grids + CELL_LOC loc = f.getLocation(); + ASSERT1(localmesh->StaggerGrids || loc == CELL_CENTRE); + bndry->first(); // Decide which generator to use @@ -997,180 +994,169 @@ void BoundaryDirichlet_O4::apply(Field2D &f,BoutReal t) { fg = f.getBndryGenerator(bndry->location); BoutReal val = 0.0; - - // Check for staggered grids - - CELL_LOC loc = f.getLocation(); - if(mesh->StaggerGrids && loc != CELL_CENTRE) { - // Staggered. Need to apply slightly differently - - if(loc == CELL_XLOW ) { - // Field is shifted in X - - if(bndry->bx > 0) { - // Outer x boundary - - for(; !bndry->isDone(); bndry->next1d()) { - if(fg) { - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) + mesh->GlobalX(bndry->x - bndry->bx) ); - BoutReal ynorm = mesh->GlobalY(bndry->y); - val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); - } - f(bndry->x,bndry->y) = val; - - // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives - for(int i=1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi) = 4.0*f(xi - bndry->bx, yi - bndry->by) - 6.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) - + 4.0*f(xi - 3*bndry->bx, yi - 3*bndry->by) - f(xi - 4*bndry->bx, yi - 4*bndry->by); - } - } + if(loc == CELL_XLOW ) { + // Field is shifted in X + + if(bndry->bx > 0) { + // Outer x boundary + + for(; !bndry->isDone(); bndry->next1d()) { + if(fg) { + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) + localmesh->GlobalX(bndry->x - bndry->bx) ); + BoutReal ynorm = localmesh->GlobalY(bndry->y); + val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); + } + f(bndry->x,bndry->y) = val; + + // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives + for(int i=1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi) = 4.0*f(xi - bndry->bx, yi - bndry->by) - 6.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + + 4.0*f(xi - 3*bndry->bx, yi - 3*bndry->by) - f(xi - 4*bndry->bx, yi - 4*bndry->by); + } } - - if(bndry->bx < 0) { - // Inner boundary. Set one point inwards - for(; !bndry->isDone(); bndry->next1d()) { - if(fg) { - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) - + mesh->GlobalX(bndry->x - bndry->bx) ); - BoutReal ynorm = mesh->GlobalY(bndry->y); - val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); - } - - f(bndry->x - bndry->bx,bndry->y) = val; + } - // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives - for(int i=0;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi) = 4.0*f(xi - bndry->bx, yi - bndry->by) - 6.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) - + 4.0*f(xi - 3*bndry->bx, yi - 3*bndry->by) - f(xi - 4*bndry->bx, yi - 4*bndry->by); - } - } + if(bndry->bx < 0) { + // Inner boundary. Set one point inwards + for(; !bndry->isDone(); bndry->next1d()) { + if(fg) { + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) + + localmesh->GlobalX(bndry->x - bndry->bx) ); + BoutReal ynorm = localmesh->GlobalY(bndry->y); + val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); + } + + f(bndry->x - bndry->bx,bndry->y) = val; + + // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives + for(int i=0;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi) = 4.0*f(xi - bndry->bx, yi - bndry->by) - 6.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + + 4.0*f(xi - 3*bndry->bx, yi - 3*bndry->by) - f(xi - 4*bndry->bx, yi - 4*bndry->by); + } } - if (bndry->by != 0){ - // y boundaries - for(; !bndry->isDone(); bndry->next1d()) { - - if(fg) { - // x norm is shifted by half a grid point because it is staggered. - // y norm is located half way between first grid cell and guard cell. - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) + mesh->GlobalX(bndry->x - 1) ); - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) + mesh->GlobalY(bndry->y - bndry->by) ); - val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); - } - - f(bndry->x,bndry->y) = (16./5)*val - 3.*f(bndry->x-bndry->bx, bndry->y-bndry->by) + f(bndry->x-2*bndry->bx, bndry->y-2*bndry->by) - (1./5)*f(bndry->x-3*bndry->bx, bndry->y-3*bndry->by); - - // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives - for(int i=1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi) = 4.0*f(xi - bndry->bx, yi - bndry->by) - 6.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) - + 4.0*f(xi - 3*bndry->bx, yi - 3*bndry->by) - f(xi - 4*bndry->bx, yi - 4*bndry->by); - } - } + } + if (bndry->by != 0){ + // y boundaries + for(; !bndry->isDone(); bndry->next1d()) { + + if(fg) { + // x norm is shifted by half a grid point because it is staggered. + // y norm is located half way between first grid cell and guard cell. + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) + localmesh->GlobalX(bndry->x - 1) ); + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) + localmesh->GlobalY(bndry->y - bndry->by) ); + val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); + } + + f(bndry->x,bndry->y) = (16./5)*val - 3.*f(bndry->x-bndry->bx, bndry->y-bndry->by) + f(bndry->x-2*bndry->bx, bndry->y-2*bndry->by) - (1./5)*f(bndry->x-3*bndry->bx, bndry->y-3*bndry->by); + + // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives + for(int i=1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi) = 4.0*f(xi - bndry->bx, yi - bndry->by) - 6.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + + 4.0*f(xi - 3*bndry->bx, yi - 3*bndry->by) - f(xi - 4*bndry->bx, yi - 4*bndry->by); + } } } - else if( loc == CELL_YLOW ) { - // Field is shifted in Y - - if(bndry->by > 0) { - // Outer y boundary - - for(; !bndry->isDone(); bndry->next1d()) { - if(fg) { - BoutReal xnorm = mesh->GlobalX(bndry->x); - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) - + mesh->GlobalY(bndry->y - bndry->by) ); - val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); - } - f(bndry->x,bndry->y) = val; - - // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives - for(int i=1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi) = 4.0*f(xi - bndry->bx, yi - bndry->by) - 6.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) - + 4.0*f(xi - 3*bndry->bx, yi - 3*bndry->by) - f(xi - 4*bndry->bx, yi - 4*bndry->by); - } - } + } else if( loc == CELL_YLOW ) { + // Field is shifted in Y + + if(bndry->by > 0) { + // Outer y boundary + + for(; !bndry->isDone(); bndry->next1d()) { + if(fg) { + BoutReal xnorm = localmesh->GlobalX(bndry->x); + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) + + localmesh->GlobalY(bndry->y - bndry->by) ); + val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); + } + f(bndry->x,bndry->y) = val; + + // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives + for(int i=1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi) = 4.0*f(xi - bndry->bx, yi - bndry->by) - 6.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + + 4.0*f(xi - 3*bndry->bx, yi - 3*bndry->by) - f(xi - 4*bndry->bx, yi - 4*bndry->by); + } } - if(bndry->by < 0) { - // Inner y boundary. Set one point inwards - for(; !bndry->isDone(); bndry->next1d()) { - if(fg) { - BoutReal xnorm = mesh->GlobalX(bndry->x); - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) - + mesh->GlobalY(bndry->y - bndry->by) ); - - val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); - } - - f(bndry->x,bndry->y - bndry->by) = val; + } + if(bndry->by < 0) { + // Inner y boundary. Set one point inwards + for(; !bndry->isDone(); bndry->next1d()) { + if(fg) { + BoutReal xnorm = localmesh->GlobalX(bndry->x); + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) + + localmesh->GlobalY(bndry->y - bndry->by) ); + + val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); + } - // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives - for(int i=0;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi) = 4.0*f(xi - bndry->bx, yi - bndry->by) - 6.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) - + 4.0*f(xi - 3*bndry->bx, yi - 3*bndry->by) - f(xi - 4*bndry->bx, yi - 4*bndry->by); - } - } + f(bndry->x,bndry->y - bndry->by) = val; + + // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives + for(int i=0;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi) = 4.0*f(xi - bndry->bx, yi - bndry->by) - 6.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + + 4.0*f(xi - 3*bndry->bx, yi - 3*bndry->by) - f(xi - 4*bndry->bx, yi - 4*bndry->by); + } } - if(bndry->bx !=0){ - // x boundaries. - - for(; !bndry->isDone(); bndry->next1d()) { - - if(fg) { - // x norm is located half way between first grid cell and guard cell. - // y norm is shifted by half a grid point because it is staggered. - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) + mesh->GlobalX(bndry->x - bndry->bx) ); - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) + mesh->GlobalY(bndry->y - 1) ); - - val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); - } - - f(bndry->x,bndry->y) = (16./5)*val - 3.*f(bndry->x-bndry->bx, bndry->y-bndry->by) + f(bndry->x-2*bndry->bx, bndry->y-2*bndry->by) - (1./5)*f(bndry->x-3*bndry->bx, bndry->y-3*bndry->by); - - // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives - for(int i=1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi) = 4.0*f(xi - bndry->bx, yi - bndry->by) - 6.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) - + 4.0*f(xi - 3*bndry->bx, yi - 3*bndry->by) - f(xi - 4*bndry->bx, yi - 4*bndry->by); - } - } + } + if(bndry->bx !=0){ + // x boundaries. + + for(; !bndry->isDone(); bndry->next1d()) { + + if(fg) { + // x norm is located half way between first grid cell and guard cell. + // y norm is shifted by half a grid point because it is staggered. + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) + localmesh->GlobalX(bndry->x - bndry->bx) ); + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) + localmesh->GlobalY(bndry->y - 1) ); + + val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); + } + + f(bndry->x,bndry->y) = (16./5)*val - 3.*f(bndry->x-bndry->bx, bndry->y-bndry->by) + f(bndry->x-2*bndry->bx, bndry->y-2*bndry->by) - (1./5)*f(bndry->x-3*bndry->bx, bndry->y-3*bndry->by); + + // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives + for(int i=1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi) = 4.0*f(xi - bndry->bx, yi - bndry->by) - 6.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + + 4.0*f(xi - 3*bndry->bx, yi - 3*bndry->by) - f(xi - 4*bndry->bx, yi - 4*bndry->by); + } } } - } - else { - // Non-staggered, standard case - + } else { + // CELL_CENTRE or CELL_ZLOW for(; !bndry->isDone(); bndry->next1d()) { - + if(fg) { - // Calculate the X and Y normalised values half-way between the guard cell and grid cell - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) // In the guard cell - + mesh->GlobalX(bndry->x - bndry->bx) ); // the grid cell - - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) // In the guard cell - + mesh->GlobalY(bndry->y - bndry->by) ); // the grid cell - - val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); + // Calculate the X and Y normalised values half-way between the guard cell and grid cell + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) // In the guard cell + + localmesh->GlobalX(bndry->x - bndry->bx) ); // the grid cell + + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) // In the guard cell + + localmesh->GlobalY(bndry->y - bndry->by) ); // the grid cell + + val = fg->generate(xnorm,TWOPI*ynorm,0.0, t); } - + f(bndry->x,bndry->y) = (16./5)*val - 3.*f(bndry->x-bndry->bx, bndry->y-bndry->by) + f(bndry->x-2*bndry->bx, bndry->y-2*bndry->by) - (1./5)*f(bndry->x-3*bndry->bx, bndry->y-3*bndry->by); - + // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives for(int i=1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi) = 4.0*f(xi - bndry->bx, yi - bndry->by) - 6.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) - + 4.0*f(xi - 3*bndry->bx, yi - 3*bndry->by) - f(xi - 4*bndry->bx, yi - 4*bndry->by); + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi) = 4.0*f(xi - bndry->bx, yi - bndry->by) - 6.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + + 4.0*f(xi - 3*bndry->bx, yi - 3*bndry->by) - f(xi - 4*bndry->bx, yi - 4*bndry->by); } } } @@ -1186,6 +1172,12 @@ void BoundaryDirichlet_O4::apply(Field3D &f,BoutReal t) { // Set (at 2nd order) the value at the mid-point between the guard cell and the grid cell to be val // N.B. Only first guard cells (closest to the grid) should ever be used + Mesh* localmesh = f.getMesh(); + + // Check for staggered grids + CELL_LOC loc = f.getLocation(); + ASSERT1(localmesh->StaggerGrids || loc == CELL_CENTRE); + bndry->first(); // Decide which generator to use @@ -1195,189 +1187,180 @@ void BoundaryDirichlet_O4::apply(Field3D &f,BoutReal t) { BoutReal val = 0.0; - // Check for staggered grids - - CELL_LOC loc = f.getLocation(); - if(mesh->StaggerGrids && loc != CELL_CENTRE) { - // Staggered. Need to apply slightly differently - - if( loc == CELL_XLOW ) { - // Field is shifted in X - - if(bndry->bx > 0) { - // Outer x boundary - - for(; !bndry->isDone(); bndry->next1d()) { - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) - + mesh->GlobalX(bndry->x - bndry->bx) ); - BoutReal ynorm = mesh->GlobalY(bndry->y); - - for(int zk=0;zkLocalNz;zk++) { - if(fg){ - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(mesh->LocalNz), t); - } - f(bndry->x,bndry->y, zk) = val; - - // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives - for(int i=1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi, zk) = 4.0*f(xi - bndry->bx, yi - bndry->by, zk) - 6.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) - + 4.0*f(xi - 3*bndry->bx, yi - 3*bndry->by, zk) - f(xi - 4*bndry->bx, yi - 4*bndry->by, zk); - } - } - } + if( loc == CELL_XLOW ) { + // Field is shifted in X + + if(bndry->bx > 0) { + // Outer x boundary + + for(; !bndry->isDone(); bndry->next1d()) { + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) + + localmesh->GlobalX(bndry->x - bndry->bx) ); + BoutReal ynorm = localmesh->GlobalY(bndry->y); + + for(int zk=0;zkLocalNz;zk++) { + if(fg){ + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(localmesh->LocalNz), t); + } + f(bndry->x,bndry->y, zk) = val; + + // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives + for(int i=1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi, zk) = 4.0*f(xi - bndry->bx, yi - bndry->by, zk) - 6.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) + + 4.0*f(xi - 3*bndry->bx, yi - 3*bndry->by, zk) - f(xi - 4*bndry->bx, yi - 4*bndry->by, zk); + } + } } - if(bndry->bx < 0) { - // Inner x boundary. Set one point inwards - for(; !bndry->isDone(); bndry->next1d()) { - - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) - + mesh->GlobalX(bndry->x - bndry->bx) ); - BoutReal ynorm = mesh->GlobalY(bndry->y); - - for(int zk=0;zkLocalNz;zk++) { - if(fg) - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(mesh->LocalNz), t); - - f(bndry->x - bndry->bx,bndry->y, zk) = val; - - // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives - for(int i=0;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi, zk) = 4.0*f(xi - bndry->bx, yi - bndry->by, zk) - 6.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) - + 4.0*f(xi - 3*bndry->bx, yi - 3*bndry->by, zk) - f(xi - 4*bndry->bx, yi - 4*bndry->by, zk); - } - } - } + } + if(bndry->bx < 0) { + // Inner x boundary. Set one point inwards + for(; !bndry->isDone(); bndry->next1d()) { + + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) + + localmesh->GlobalX(bndry->x - bndry->bx) ); + BoutReal ynorm = localmesh->GlobalY(bndry->y); + + for(int zk=0;zkLocalNz;zk++) { + if(fg) + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(localmesh->LocalNz), t); + + f(bndry->x - bndry->bx,bndry->y, zk) = val; + + // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives + for(int i=0;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi, zk) = 4.0*f(xi - bndry->bx, yi - bndry->by, zk) - 6.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) + + 4.0*f(xi - 3*bndry->bx, yi - 3*bndry->by, zk) - f(xi - 4*bndry->bx, yi - 4*bndry->by, zk); + } + } } - if (bndry->by != 0){ - // y boundaries + } + if (bndry->by != 0){ + // y boundaries - for(; !bndry->isDone(); bndry->next1d()) { - // x norm is shifted by half a grid point because it is staggered. - // y norm is located half way between first grid cell and guard cell. - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) + mesh->GlobalX(bndry->x - 1) ); - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) + mesh->GlobalY(bndry->y - bndry->by) ); - - for(int zk=0;zkLocalNz;zk++) { - if(fg) { - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(mesh->LocalNz), t); - } - f(bndry->x,bndry->y,zk) = (16./5)*val - 3.*f(bndry->x-bndry->bx, bndry->y-bndry->by,zk) + f(bndry->x-2*bndry->bx, bndry->y-2*bndry->by,zk) - (1./5)*f(bndry->x-3*bndry->bx, bndry->y-3*bndry->by,zk); - - // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives - for(int i=1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi, zk) = 4.0*f(xi - bndry->bx, yi - bndry->by, zk) - 6.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) - + 4.0*f(xi - 3*bndry->bx, yi - 3*bndry->by, zk) - f(xi - 4*bndry->bx, yi - 4*bndry->by, zk); - } + for(; !bndry->isDone(); bndry->next1d()) { + // x norm is shifted by half a grid point because it is staggered. + // y norm is located half way between first grid cell and guard cell. + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) + localmesh->GlobalX(bndry->x - 1) ); + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) + localmesh->GlobalY(bndry->y - bndry->by) ); + + for(int zk=0;zkLocalNz;zk++) { + if(fg) { + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(localmesh->LocalNz), t); + } + f(bndry->x,bndry->y,zk) = (16./5)*val - 3.*f(bndry->x-bndry->bx, bndry->y-bndry->by,zk) + f(bndry->x-2*bndry->bx, bndry->y-2*bndry->by,zk) - (1./5)*f(bndry->x-3*bndry->bx, bndry->y-3*bndry->by,zk); + + // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives + for(int i=1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi, zk) = 4.0*f(xi - bndry->bx, yi - bndry->by, zk) - 6.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) + + 4.0*f(xi - 3*bndry->bx, yi - 3*bndry->by, zk) - f(xi - 4*bndry->bx, yi - 4*bndry->by, zk); } } } } - else if( loc == CELL_YLOW ) { - // Y boundary, and field is shifted in Y - - if(bndry->by > 0) { - // Outer y boundary - - for(; !bndry->isDone(); bndry->next1d()) { - BoutReal xnorm = mesh->GlobalX(bndry->x); - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) - + mesh->GlobalY(bndry->y - bndry->by) ); - for(int zk=0;zkLocalNz;zk++) { - if(fg) - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(mesh->LocalNz), t); - - f(bndry->x,bndry->y,zk) = val; - - // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives - for(int i=1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi, zk) = 4.0*f(xi - bndry->bx, yi - bndry->by, zk) - 6.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) - + 4.0*f(xi - 3*bndry->bx, yi - 3*bndry->by, zk) - f(xi - 4*bndry->bx, yi - 4*bndry->by, zk); - } - } - } + } else if( loc == CELL_YLOW ) { + // Y boundary, and field is shifted in Y + + if(bndry->by > 0) { + // Outer y boundary + + for(; !bndry->isDone(); bndry->next1d()) { + BoutReal xnorm = localmesh->GlobalX(bndry->x); + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) + + localmesh->GlobalY(bndry->y - bndry->by) ); + for(int zk=0;zkLocalNz;zk++) { + if(fg) + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(localmesh->LocalNz), t); + + f(bndry->x,bndry->y,zk) = val; + + // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives + for(int i=1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi, zk) = 4.0*f(xi - bndry->bx, yi - bndry->by, zk) - 6.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) + + 4.0*f(xi - 3*bndry->bx, yi - 3*bndry->by, zk) - f(xi - 4*bndry->bx, yi - 4*bndry->by, zk); + } + } } - if(bndry->by < 0) { - // Inner y boundary. Set one point inwards - for(; !bndry->isDone(); bndry->next1d()) { - - BoutReal xnorm = mesh->GlobalX(bndry->x); - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) - + mesh->GlobalY(bndry->y - bndry->by) ); - - for(int zk=0;zkLocalNz;zk++) { - if(fg) - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(mesh->LocalNz), t); - - f(bndry->x,bndry->y - bndry->by, zk) = val; - - // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives - for(int i=0;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi, zk) = 4.0*f(xi - bndry->bx, yi - bndry->by, zk) - 6.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) - + 4.0*f(xi - 3*bndry->bx, yi - 3*bndry->by, zk) - f(xi - 4*bndry->bx, yi - 4*bndry->by, zk); - } - } - } + } + if(bndry->by < 0) { + // Inner y boundary. Set one point inwards + for(; !bndry->isDone(); bndry->next1d()) { + + BoutReal xnorm = localmesh->GlobalX(bndry->x); + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) + + localmesh->GlobalY(bndry->y - bndry->by) ); + + for(int zk=0;zkLocalNz;zk++) { + if(fg) + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(localmesh->LocalNz), t); + + f(bndry->x,bndry->y - bndry->by, zk) = val; + + // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives + for(int i=0;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi, zk) = 4.0*f(xi - bndry->bx, yi - bndry->by, zk) - 6.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) + + 4.0*f(xi - 3*bndry->bx, yi - 3*bndry->by, zk) - f(xi - 4*bndry->bx, yi - 4*bndry->by, zk); + } + } } - if(bndry->bx !=0){ - // x boundaries - - for(; !bndry->isDone(); bndry->next1d()) { - // x norm is located half way between first grid cell and guard cell. - // y norm is shifted by half a grid point because it is staggered. - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) + mesh->GlobalX(bndry->x - bndry->bx) ); - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) + mesh->GlobalY(bndry->y - 1) ); - - for(int zk=0;zkLocalNz;zk++) { - if(fg) - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(mesh->LocalNz), t); - - f(bndry->x,bndry->y,zk) = (16./5)*val - 3.*f(bndry->x-bndry->bx, bndry->y-bndry->by,zk) + f(bndry->x-2*bndry->bx, bndry->y-2*bndry->by,zk) - (1./5)*f(bndry->x-3*bndry->bx, bndry->y-3*bndry->by,zk); - - // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives - for(int i=1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi, zk) = 4.0*f(xi - bndry->bx, yi - bndry->by, zk) - 6.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) - + 4.0*f(xi - 3*bndry->bx, yi - 3*bndry->by, zk) - f(xi - 4*bndry->bx, yi - 4*bndry->by, zk); - } - } - } + } + if(bndry->bx !=0){ + // x boundaries + + for(; !bndry->isDone(); bndry->next1d()) { + // x norm is located half way between first grid cell and guard cell. + // y norm is shifted by half a grid point because it is staggered. + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) + localmesh->GlobalX(bndry->x - bndry->bx) ); + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) + localmesh->GlobalY(bndry->y - 1) ); + + for(int zk=0;zkLocalNz;zk++) { + if(fg) + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(localmesh->LocalNz), t); + + f(bndry->x,bndry->y,zk) = (16./5)*val - 3.*f(bndry->x-bndry->bx, bndry->y-bndry->by,zk) + f(bndry->x-2*bndry->bx, bndry->y-2*bndry->by,zk) - (1./5)*f(bndry->x-3*bndry->bx, bndry->y-3*bndry->by,zk); + + // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives + for(int i=1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi, zk) = 4.0*f(xi - bndry->bx, yi - bndry->by, zk) - 6.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) + + 4.0*f(xi - 3*bndry->bx, yi - 3*bndry->by, zk) - f(xi - 4*bndry->bx, yi - 4*bndry->by, zk); + } + } } } - } - else { - // Standard (non-staggered) case + } else { + // CELL_CENTRE or CELL_ZLOW for(; !bndry->isDone(); bndry->next1d()) { - // Calculate the X and Y normalised values half-way between the guard cell and grid cell - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) // In the guard cell - + mesh->GlobalX(bndry->x - bndry->bx) ); // the grid cell + // Calculate the X and Y normalised values half-way between the guard cell and grid cell + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) // In the guard cell + + localmesh->GlobalX(bndry->x - bndry->bx) ); // the grid cell - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) // In the guard cell - + mesh->GlobalY(bndry->y - bndry->by) ); // the grid cell - - for(int zk=0;zkLocalNz;zk++) { - if(fg) - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(mesh->LocalNz), t); - - f(bndry->x,bndry->y,zk) = (16./5)*val - 3.*f(bndry->x-bndry->bx, bndry->y-bndry->by,zk) + f(bndry->x-2*bndry->bx, bndry->y-2*bndry->by,zk) - (1./5)*f(bndry->x-3*bndry->bx, bndry->y-3*bndry->by,zk); - - // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives - for(int i=1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi, zk) = 4.0*f(xi - bndry->bx, yi - bndry->by, zk) - 6.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) - + 4.0*f(xi - 3*bndry->bx, yi - 3*bndry->by, zk) - f(xi - 4*bndry->bx, yi - 4*bndry->by, zk); - } + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) // In the guard cell + + localmesh->GlobalY(bndry->y - bndry->by) ); // the grid cell + + for(int zk=0;zkLocalNz;zk++) { + if(fg) + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(localmesh->LocalNz), t); + + f(bndry->x,bndry->y,zk) = (16./5)*val - 3.*f(bndry->x-bndry->bx, bndry->y-bndry->by,zk) + f(bndry->x-2*bndry->bx, bndry->y-2*bndry->by,zk) - (1./5)*f(bndry->x-3*bndry->bx, bndry->y-3*bndry->by,zk); + + // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives + for(int i=1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi, zk) = 4.0*f(xi - bndry->bx, yi - bndry->by, zk) - 6.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) + + 4.0*f(xi - 3*bndry->bx, yi - 3*bndry->by, zk) - f(xi - 4*bndry->bx, yi - 4*bndry->by, zk); + } } } } @@ -1390,9 +1373,10 @@ void BoundaryDirichlet_O4::apply_ddt(Field2D &f) { } void BoundaryDirichlet_O4::apply_ddt(Field3D &f) { + Mesh* localmesh = f.getMesh(); Field3D *dt = f.timeDeriv(); for(bndry->first(); !bndry->isDone(); bndry->next()) - for(int z=0;zLocalNz;z++) + for(int z=0;zLocalNz;z++) (*dt)(bndry->x,bndry->y,z) = 0.; // Set time derivative to zero } @@ -1401,7 +1385,7 @@ void BoundaryDirichlet_O4::apply_ddt(Field3D &f) { BoundaryOp* BoundaryDirichlet_2ndOrder::clone(BoundaryRegion *region, const list &args) { output << "WARNING: Use of boundary condition \"dirichlet_2ndorder\" is deprecated!\n"; output << " Consider using \"dirichlet\" instead\n"; - verifyNumPoints(region,2); + verifyNumPoints(region, 2); if(!args.empty()) { // First argument should be a value val = stringToReal(args.front()); @@ -1424,10 +1408,11 @@ void BoundaryDirichlet_2ndOrder::apply(Field2D &f) { } void BoundaryDirichlet_2ndOrder::apply(Field3D &f) { + Mesh* localmesh = f.getMesh(); // Set (at 2nd order) the value at the mid-point between the guard cell and the grid cell to be val // N.B. Only first guard cells (closest to the grid) should ever be used for(bndry->first(); !bndry->isDone(); bndry->next1d()) - for(int z=0;zLocalNz;z++) { + for(int z=0;zLocalNz;z++) { f(bndry->x,bndry->y,z) = 8./3.*val - 2.*f(bndry->x-bndry->bx,bndry->y-bndry->by,z) + 1./3.*f(bndry->x-2*bndry->bx,bndry->y-2*bndry->by,z); #ifdef BOUNDARY_CONDITIONS_UPGRADE_EXTRAPOLATE_FOR_2ND_ORDER f(bndry->x+bndry->bx,bndry->y+bndry->by,z) = 3.*f(bndry->x,bndry->y,z) - 3.*f(bndry->x-bndry->bx,bndry->y-bndry->by,z) + f(bndry->x-2*bndry->bx,bndry->y-2*bndry->by,z); @@ -1444,16 +1429,17 @@ void BoundaryDirichlet_2ndOrder::apply_ddt(Field2D &f) { } void BoundaryDirichlet_2ndOrder::apply_ddt(Field3D &f) { + Mesh* localmesh = f.getMesh(); Field3D *dt = f.timeDeriv(); for(bndry->first(); !bndry->isDone(); bndry->next()) - for(int z=0;zLocalNz;z++) + for(int z=0;zLocalNz;z++) (*dt)(bndry->x,bndry->y,z) = 0.; // Set time derivative to zero } /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryDirichlet_4thOrder::clone(BoundaryRegion *region, const list &args) { - verifyNumPoints(region,4); + verifyNumPoints(region, 4); if(!args.empty()) { // First argument should be a value val = stringToReal(args.front()); @@ -1471,9 +1457,10 @@ void BoundaryDirichlet_4thOrder::apply(Field2D &f) { } void BoundaryDirichlet_4thOrder::apply(Field3D &f) { + Mesh* localmesh = f.getMesh(); // Set (at 4th order) the value at the mid-point between the guard cell and the grid cell to be val for(bndry->first(); !bndry->isDone(); bndry->next1d()) - for(int z=0;zLocalNz;z++) { + for(int z=0;zLocalNz;z++) { f(bndry->x,bndry->y,z) = 128./35.*val - 4.*f(bndry->x-bndry->bx,bndry->y-bndry->by,z) + 2.*f(bndry->x-2*bndry->bx,bndry->y-2*bndry->by,z) - 4./3.*f(bndry->x-3*bndry->bx,bndry->y-3*bndry->by,z) + 1./7.*f(bndry->x-4*bndry->bx,bndry->y-4*bndry->by,z); f(bndry->x+bndry->bx,bndry->y+bndry->by,z) = -128./5.*val + 9.*f(bndry->x,bndry->y,z) + 18.*f(bndry->x-bndry->bx,bndry->y-bndry->by,z) -4.*f(bndry->x-2*bndry->bx,bndry->y-2*bndry->by,z) + 3./5.*f(bndry->x-3*bndry->bx,bndry->y-3*bndry->by,z); } @@ -1486,16 +1473,17 @@ void BoundaryDirichlet_4thOrder::apply_ddt(Field2D &f) { } void BoundaryDirichlet_4thOrder::apply_ddt(Field3D &f) { + Mesh* localmesh = f.getMesh(); Field3D *dt = f.timeDeriv(); for(bndry->first(); !bndry->isDone(); bndry->next()) - for(int z=0;zLocalNz;z++) + for(int z=0;zLocalNz;z++) (*dt)(bndry->x,bndry->y,z) = 0.; // Set time derivative to zero } /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryNeumann_NonOrthogonal::clone(BoundaryRegion *region, const list &args) { - verifyNumPoints(region,1); + verifyNumPoints(region, 1); if(!args.empty()) { output << "WARNING: arguments is set to BoundaryNeumann None Zero Gradient\n"; // First argument should be a value @@ -1506,9 +1494,10 @@ BoundaryOp* BoundaryNeumann_NonOrthogonal::clone(BoundaryRegion *region, const l } void BoundaryNeumann_NonOrthogonal::apply(Field2D &f) { + Mesh* localmesh = f.getMesh(); Coordinates *metric = f.getCoordinates(); // Calculate derivatives for metric use - mesh->communicate(f); + localmesh->communicate(f); Field2D dfdy = DDY(f); // Loop over all elements and set equal to the next point in for(bndry->first(); !bndry->isDone(); bndry->next1d()) { @@ -1546,9 +1535,10 @@ void BoundaryNeumann_NonOrthogonal::apply(Field2D &f) { } void BoundaryNeumann_NonOrthogonal::apply(Field3D &f) { + Mesh* localmesh = f.getMesh(); Coordinates *metric = f.getCoordinates(); // Calculate derivatives for metric use - mesh->communicate(f); + localmesh->communicate(f); Field3D dfdy = DDY(f); Field3D dfdz = DDZ(f); // Loop over all elements and set equal to the next point in @@ -1560,7 +1550,7 @@ void BoundaryNeumann_NonOrthogonal::apply(Field3D &f) { // Have to use derivatives at last gridpoint instead of derivatives on boundary layer // because derivative values don't exist in boundary region // NOTE: should be fixed to interpolate to boundary line - for(int z=0;zLocalNz;z++) { + for(int z=0;zLocalNz;z++) { BoutReal xshift = g12shift*dfdy(bndry->x-bndry->bx,bndry->y,z) + g13shift*dfdz(bndry->x-bndry->bx,bndry->y,z); if(bndry->bx != 0 && bndry->by == 0) { @@ -1594,7 +1584,7 @@ void BoundaryNeumann_NonOrthogonal::apply(Field3D &f) { BoundaryOp* BoundaryNeumann2::clone(BoundaryRegion *region, const list &args) { output << "WARNING: Use of boundary condition \"neumann2\" is deprecated!\n"; output << " Consider using \"neumann\" instead\n"; - verifyNumPoints(region,2); + verifyNumPoints(region, 2); if(!args.empty()) { output << "WARNING: Ignoring arguments to BoundaryNeumann2\n"; } @@ -1608,8 +1598,9 @@ void BoundaryNeumann2::apply(Field2D &f) { } void BoundaryNeumann2::apply(Field3D &f) { + Mesh* localmesh = f.getMesh(); for(bndry->first(); !bndry->isDone(); bndry->next()) - for(int z=0;zLocalNz;z++) + for(int z=0;zLocalNz;z++) f(bndry->x, bndry->y, z) = (4.*f(bndry->x - bndry->bx, bndry->y - bndry->by, z) - f(bndry->x - 2*bndry->bx, bndry->y - 2*bndry->by, z))/3.; } @@ -1619,9 +1610,9 @@ BoundaryOp* BoundaryNeumann_2ndOrder::clone(BoundaryRegion *region, const listfirst(); !bndry->isDone(); bndry->next1d()) - for(int z=0;zLocalNz;z++) { + for(int z=0;zLocalNz;z++) { BoutReal delta = bndry->bx*metric->dx(bndry->x,bndry->y)+bndry->by*metric->dy(bndry->x,bndry->y); f(bndry->x,bndry->y,z) = f(bndry->x-bndry->bx,bndry->y-bndry->by,z) + val*delta; #ifdef BOUNDARY_CONDITIONS_UPGRADE_EXTRAPOLATE_FOR_2ND_ORDER @@ -1671,16 +1663,17 @@ void BoundaryNeumann_2ndOrder::apply_ddt(Field2D &f) { } void BoundaryNeumann_2ndOrder::apply_ddt(Field3D &f) { + Mesh* localmesh = f.getMesh(); Field3D *dt = f.timeDeriv(); for(bndry->first(); !bndry->isDone(); bndry->next()) - for(int z=0;zLocalNz;z++) + for(int z=0;zLocalNz;z++) (*dt)(bndry->x,bndry->y,z) = 0.; // Set time derivative to zero } /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryNeumann::clone(BoundaryRegion *region, const list &args){ - verifyNumPoints(region,1); + verifyNumPoints(region, 1); std::shared_ptr newgen = nullptr; if(!args.empty()) { // First argument should be an expression @@ -1697,192 +1690,188 @@ void BoundaryNeumann::apply(Field2D &f) { void BoundaryNeumann::apply(Field2D &f,BoutReal t) { // Set (at 2nd order) the value at the mid-point between the guard cell and the grid cell to be val // N.B. Only first guard cells (closest to the grid) should ever be used - + + Mesh* localmesh = f.getMesh(); + + // Check for staggered grids + CELL_LOC loc = f.getLocation(); + ASSERT1(localmesh->StaggerGrids || loc == CELL_CENTRE); + Coordinates *metric = f.getCoordinates(); - + bndry->first(); - + // Decide which generator to use std::shared_ptr fg = gen; if(!fg) fg = f.getBndryGenerator(bndry->location); - + BoutReal val = 0.0; - - // Check for staggered grids - - CELL_LOC loc = f.getLocation(); - if(mesh->StaggerGrids && loc != CELL_CENTRE) { - // Staggered. Need to apply slightly differently - // Use one-sided differencing. Cell is now on - // the boundary, so use one-sided differencing - - if( loc == CELL_XLOW ) { - // Field is shifted in X - - if(bndry->bx > 0) { - // Outer x boundary - - for(; !bndry->isDone(); bndry->next1d()) { - - if(fg) { - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) - + mesh->GlobalX(bndry->x - bndry->bx) ); - BoutReal ynorm = mesh->GlobalY(bndry->y); - - val = fg->generate(xnorm,TWOPI*ynorm,0.0, t) * metric->dx(bndry->x, bndry->y); - } - - f(bndry->x,bndry->y) = (4.*f(bndry->x - bndry->bx, bndry->y) - f(bndry->x - 2*bndry->bx, bndry->y) + 2.*val)/3.; - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - // Use third order extrapolation because boundary point is set to third order, and these points - // may be used be used by 2nd order upwinding type schemes, which require 3rd order - f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); - } - } + + // For staggered case need to apply slightly differently Use one-sided + // differencing. Cell is now on the boundary, so use one-sided differencing + if( loc == CELL_XLOW ) { + // Field is shifted in X + + if(bndry->bx > 0) { + // Outer x boundary + + for(; !bndry->isDone(); bndry->next1d()) { + + if(fg) { + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) + + localmesh->GlobalX(bndry->x - bndry->bx) ); + BoutReal ynorm = localmesh->GlobalY(bndry->y); + + val = fg->generate(xnorm,TWOPI*ynorm,0.0, t) * metric->dx(bndry->x, bndry->y); + } + + f(bndry->x,bndry->y) = (4.*f(bndry->x - bndry->bx, bndry->y) - f(bndry->x - 2*bndry->bx, bndry->y) + 2.*val)/3.; + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + // Use third order extrapolation because boundary point is set to third order, and these points + // may be used be used by 2nd order upwinding type schemes, which require 3rd order + f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); + } } - if(bndry->bx < 0) { - // Inner x boundary. Set one point inwards - for(; !bndry->isDone(); bndry->next1d()) { - - if(fg) { - - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) - + mesh->GlobalX(bndry->x - bndry->bx) ); - BoutReal ynorm = mesh->GlobalY(bndry->y); - - val = fg->generate(xnorm,TWOPI*ynorm,0.0, t) * metric->dx(bndry->x, bndry->y); - } - - f(bndry->x - bndry->bx,bndry->y) = (4.*f(bndry->x - 2*bndry->bx, bndry->y) - f(bndry->x - 3*bndry->bx, bndry->y) - 2.*val)/3.; - - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=0;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - // Use third order extrapolation because boundary point is set to third order, and these points - // may be used be used by 2nd order upwinding type schemes, which require 3rd order - f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); - } - } + } + if(bndry->bx < 0) { + // Inner x boundary. Set one point inwards + for(; !bndry->isDone(); bndry->next1d()) { + + if(fg) { + + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) + + localmesh->GlobalX(bndry->x - bndry->bx) ); + BoutReal ynorm = localmesh->GlobalY(bndry->y); + + val = fg->generate(xnorm,TWOPI*ynorm,0.0, t) * metric->dx(bndry->x, bndry->y); + } + + f(bndry->x - bndry->bx,bndry->y) = (4.*f(bndry->x - 2*bndry->bx, bndry->y) - f(bndry->x - 3*bndry->bx, bndry->y) - 2.*val)/3.; + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=0;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + // Use third order extrapolation because boundary point is set to third order, and these points + // may be used be used by 2nd order upwinding type schemes, which require 3rd order + f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); + } } - if(bndry->by !=0 ){ - // y boundaries - - for(bndry->first(); !bndry->isDone(); bndry->next1d()) { - BoutReal delta = bndry->bx*metric->dx(bndry->x,bndry->y)+bndry->by*metric->dy(bndry->x,bndry->y); - - if(fg) { - // x norm is shifted by half a grid point because it is staggered. - // y norm is located half way between first grid cell and guard cell. - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) + mesh->GlobalX(bndry->x - 1) ); - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) + mesh->GlobalY(bndry->y - bndry->by) ); - - val = fg->generate(xnorm, TWOPI*ynorm, 0.0, t); - } - - f(bndry->x,bndry->y) = f(bndry->x-bndry->bx, bndry->y-bndry->by) + delta*val; - if (bndry->width == 2){ - f(bndry->x + bndry->bx, bndry->y + bndry->by) = f(bndry->x - 2*bndry->bx, bndry->y - 2*bndry->by) + 3.0*delta*val; - } - } + } + if(bndry->by !=0 ){ + // y boundaries + + for(bndry->first(); !bndry->isDone(); bndry->next1d()) { + BoutReal delta = bndry->bx*metric->dx(bndry->x,bndry->y)+bndry->by*metric->dy(bndry->x,bndry->y); + + if(fg) { + // x norm is shifted by half a grid point because it is staggered. + // y norm is located half way between first grid cell and guard cell. + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) + localmesh->GlobalX(bndry->x - 1) ); + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) + localmesh->GlobalY(bndry->y - bndry->by) ); + + val = fg->generate(xnorm, TWOPI*ynorm, 0.0, t); + } + + f(bndry->x,bndry->y) = f(bndry->x-bndry->bx, bndry->y-bndry->by) + delta*val; + if (bndry->width == 2){ + f(bndry->x + bndry->bx, bndry->y + bndry->by) = f(bndry->x - 2*bndry->bx, bndry->y - 2*bndry->by) + 3.0*delta*val; + } } } - else if(loc == CELL_YLOW) { - // Y boundary, and field is shifted in Y - - if(bndry->by > 0) { - // Outer y boundary - - for(; !bndry->isDone(); bndry->next1d()) { - if(fg) { - BoutReal xnorm = mesh->GlobalX(bndry->x); - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) - + mesh->GlobalY(bndry->y - bndry->by) ); - - val = fg->generate(xnorm,TWOPI*ynorm,0.0, t) * metric->dx(bndry->x, bndry->y); - } - f(bndry->x,bndry->y) = (4.*f(bndry->x, bndry->y - bndry->by) - f(bndry->x, bndry->y - 2*bndry->by) + 2.*val)/3.; - - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - // Use third order extrapolation because boundary point is set to third order, and these points - // may be used be used by 2nd order upwinding type schemes, which require 3rd order - f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); - } - } + } else if(loc == CELL_YLOW) { + // Y boundary, and field is shifted in Y + + if(bndry->by > 0) { + // Outer y boundary + + for(; !bndry->isDone(); bndry->next1d()) { + if(fg) { + BoutReal xnorm = localmesh->GlobalX(bndry->x); + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) + + localmesh->GlobalY(bndry->y - bndry->by) ); + + val = fg->generate(xnorm,TWOPI*ynorm,0.0, t) * metric->dx(bndry->x, bndry->y); + } + f(bndry->x,bndry->y) = (4.*f(bndry->x, bndry->y - bndry->by) - f(bndry->x, bndry->y - 2*bndry->by) + 2.*val)/3.; + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + // Use third order extrapolation because boundary point is set to third order, and these points + // may be used be used by 2nd order upwinding type schemes, which require 3rd order + f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); + } } - if(bndry->by < 0) { - // Inner y boundary. Set one point inwards - for(; !bndry->isDone(); bndry->next1d()) { - - if(fg) { - - BoutReal xnorm = mesh->GlobalX(bndry->x); - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) - + mesh->GlobalY(bndry->y - bndry->by) ); - - val = fg->generate(xnorm,TWOPI*ynorm,0.0, t) * metric->dx(bndry->x, bndry->y - bndry->by); - } - f(bndry->x,bndry->y - bndry->by) = (4.*f(bndry->x, bndry->y - 2*bndry->by) - f(bndry->x, bndry->y - 3*bndry->by) - 2.*val)/3.; - - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=0;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - // Use third order extrapolation because boundary point is set to third order, and these points - // may be used be used by 2nd order upwinding type schemes, which require 3rd order - f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); - } - } + } + if(bndry->by < 0) { + // Inner y boundary. Set one point inwards + for(; !bndry->isDone(); bndry->next1d()) { + + if(fg) { + + BoutReal xnorm = localmesh->GlobalX(bndry->x); + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) + + localmesh->GlobalY(bndry->y - bndry->by) ); + + val = fg->generate(xnorm,TWOPI*ynorm,0.0, t) * metric->dx(bndry->x, bndry->y - bndry->by); + } + f(bndry->x,bndry->y - bndry->by) = (4.*f(bndry->x, bndry->y - 2*bndry->by) - f(bndry->x, bndry->y - 3*bndry->by) - 2.*val)/3.; + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=0;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + // Use third order extrapolation because boundary point is set to third order, and these points + // may be used be used by 2nd order upwinding type schemes, which require 3rd order + f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); + } } - if(bndry->bx != 0){ - // x boundaries - for(bndry->first(); !bndry->isDone(); bndry->next1d()) { - BoutReal delta = bndry->bx*metric->dx(bndry->x,bndry->y)+bndry->by*metric->dy(bndry->x,bndry->y); - - if(fg) { - // x norm is located half way between first grid cell and guard cell. - // y norm is shifted by half a grid point because it is staggered. - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) + mesh->GlobalX(bndry->x - bndry->bx) ); - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) + mesh->GlobalY(bndry->y - 1) ); - - val = fg->generate(xnorm, TWOPI*ynorm, 0.0, t); - } - - f(bndry->x,bndry->y) = f(bndry->x-bndry->bx, bndry->y-bndry->by) + delta*val; - if (bndry->width == 2){ - f(bndry->x + bndry->bx, bndry->y + bndry->by) = f(bndry->x - 2*bndry->bx, bndry->y - 2*bndry->by) + 3.0*delta*val; - } - } - } } - } - else { - // Non-staggered, standard case - + if(bndry->bx != 0){ + // x boundaries + for(bndry->first(); !bndry->isDone(); bndry->next1d()) { + BoutReal delta = bndry->bx*metric->dx(bndry->x,bndry->y)+bndry->by*metric->dy(bndry->x,bndry->y); + + if(fg) { + // x norm is located half way between first grid cell and guard cell. + // y norm is shifted by half a grid point because it is staggered. + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) + localmesh->GlobalX(bndry->x - bndry->bx) ); + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) + localmesh->GlobalY(bndry->y - 1) ); + + val = fg->generate(xnorm, TWOPI*ynorm, 0.0, t); + } + + f(bndry->x,bndry->y) = f(bndry->x-bndry->bx, bndry->y-bndry->by) + delta*val; + if (bndry->width == 2){ + f(bndry->x + bndry->bx, bndry->y + bndry->by) = f(bndry->x - 2*bndry->bx, bndry->y - 2*bndry->by) + 3.0*delta*val; + } + } + } + } else { + // CELL_CENTRE or CELL_ZLOW for(bndry->first(); !bndry->isDone(); bndry->next1d()) { BoutReal delta = bndry->bx*metric->dx(bndry->x,bndry->y)+bndry->by*metric->dy(bndry->x,bndry->y); - + if(fg) { - // Calculate the X and Y normalised values half-way between the guard cell and grid cell - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) // In the guard cell - + mesh->GlobalX(bndry->x - bndry->bx) ); // the grid cell - - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) // In the guard cell - + mesh->GlobalY(bndry->y - bndry->by) ); // the grid cell - - val = fg->generate(xnorm, TWOPI*ynorm, 0.0, t); + // Calculate the X and Y normalised values half-way between the guard cell and grid cell + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) // In the guard cell + + localmesh->GlobalX(bndry->x - bndry->bx) ); // the grid cell + + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) // In the guard cell + + localmesh->GlobalY(bndry->y - bndry->by) ); // the grid cell + + val = fg->generate(xnorm, TWOPI*ynorm, 0.0, t); } - + f(bndry->x,bndry->y) = f(bndry->x-bndry->bx, bndry->y-bndry->by) + delta*val; if (bndry->width == 2){ - f(bndry->x + bndry->bx, bndry->y + bndry->by) = f(bndry->x - 2*bndry->bx, bndry->y - 2*bndry->by) + 3.0*delta*val; + f(bndry->x + bndry->bx, bndry->y + bndry->by) = f(bndry->x - 2*bndry->bx, bndry->y - 2*bndry->by) + 3.0*delta*val; } } } @@ -1895,197 +1884,197 @@ void BoundaryNeumann::apply(Field3D &f) { void BoundaryNeumann::apply(Field3D &f,BoutReal t) { + + Mesh* localmesh = f.getMesh(); + + // Check for staggered grids + CELL_LOC loc = f.getLocation(); + ASSERT1(localmesh->StaggerGrids || loc == CELL_CENTRE); + Coordinates *metric = f.getCoordinates(); - + bndry->first(); - + // Decide which generator to use std::shared_ptr fg = gen; if(!fg) fg = f.getBndryGenerator(bndry->location); - + BoutReal val = 0.0; - - // Check for staggered grids - - CELL_LOC loc = f.getLocation(); - if(mesh->StaggerGrids && loc != CELL_CENTRE) { - // Staggered. Need to apply slightly differently - // Use one-sided differencing. Cell is now on - // the boundary, so use one-sided differencing - - if( loc == CELL_XLOW ) { - // Field is shifted in X - - if(bndry->bx > 0) { - // Outer x boundary - for(; !bndry->isDone(); bndry->next1d()) { - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) - + mesh->GlobalX(bndry->x - bndry->bx) ); - BoutReal ynorm = mesh->GlobalY(bndry->y); - - for(int zk=0;zkLocalNz;zk++) { - if(fg) - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(mesh->LocalNz),t) * metric->dx(bndry->x, bndry->y); - - f(bndry->x,bndry->y, zk) = (4.*f(bndry->x - bndry->bx, bndry->y,zk) - f(bndry->x - 2*bndry->bx, bndry->y,zk) + 2.*val)/3.; - - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - // Use third order extrapolation because boundary point is set to third order, and these points - // may be used be used by 2nd order upwinding type schemes, which require 3rd order - f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) - + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); - } - } - } + + // For staggered case need to apply slightly differently Use one-sided + // differencing. Cell is now on the boundary, so use one-sided differencing + + if( loc == CELL_XLOW ) { + // Field is shifted in X + + if(bndry->bx > 0) { + // Outer x boundary + for(; !bndry->isDone(); bndry->next1d()) { + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) + + localmesh->GlobalX(bndry->x - bndry->bx) ); + BoutReal ynorm = localmesh->GlobalY(bndry->y); + + for(int zk=0;zkLocalNz;zk++) { + if(fg) + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(localmesh->LocalNz),t) * metric->dx(bndry->x, bndry->y); + + f(bndry->x,bndry->y, zk) = (4.*f(bndry->x - bndry->bx, bndry->y,zk) - f(bndry->x - 2*bndry->bx, bndry->y,zk) + 2.*val)/3.; + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + // Use third order extrapolation because boundary point is set to third order, and these points + // may be used be used by 2nd order upwinding type schemes, which require 3rd order + f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) + + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); + } + } } - if(bndry->bx < 0) { - // Inner x boundary - for(; !bndry->isDone(); bndry->next1d()) { - - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) - + mesh->GlobalX(bndry->x - bndry->bx) ); - BoutReal ynorm = mesh->GlobalY(bndry->y); - - for(int zk=0;zkLocalNz;zk++) { - - if(fg) - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(mesh->LocalNz),t) * metric->dx(bndry->x - bndry->bx, bndry->y); - - f(bndry->x - bndry->bx,bndry->y, zk) = (4.*f(bndry->x - 2*bndry->bx, bndry->y,zk) - f(bndry->x - 3*bndry->bx, bndry->y,zk) - 2.*val)/3.; - - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=0;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - // Use third order extrapolation because boundary point is set to third order, and these points - // may be used be used by 2nd order upwinding type schemes, which require 3rd order - f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) - + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); - } - } - } + } + if(bndry->bx < 0) { + // Inner x boundary + for(; !bndry->isDone(); bndry->next1d()) { + + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) + + localmesh->GlobalX(bndry->x - bndry->bx) ); + BoutReal ynorm = localmesh->GlobalY(bndry->y); + + for(int zk=0;zkLocalNz;zk++) { + + if(fg) + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(localmesh->LocalNz),t) * metric->dx(bndry->x - bndry->bx, bndry->y); + + f(bndry->x - bndry->bx,bndry->y, zk) = (4.*f(bndry->x - 2*bndry->bx, bndry->y,zk) - f(bndry->x - 3*bndry->bx, bndry->y,zk) - 2.*val)/3.; + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=0;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + // Use third order extrapolation because boundary point is set to third order, and these points + // may be used be used by 2nd order upwinding type schemes, which require 3rd order + f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) + + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); + } + } } - if(bndry->by != 0) { - for(; !bndry->isDone(); bndry->next1d()) { - // x norm is shifted by half a grid point because it is staggered. - // y norm is located half way between first grid cell and guard cell. - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) + mesh->GlobalX(bndry->x - 1) ); - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) + mesh->GlobalY(bndry->y - bndry->by) ); - - BoutReal delta = bndry->bx*metric->dx(bndry->x,bndry->y)+bndry->by*metric->dy(bndry->x,bndry->y); - - for(int zk=0;zkLocalNz;zk++) { - if(fg){ - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(mesh->LocalNz),t); - } - f(bndry->x,bndry->y, zk) = f(bndry->x-bndry->bx, bndry->y-bndry->by, zk) + delta*val; - if (bndry->width == 2){ - f(bndry->x + bndry->bx, bndry->y + bndry->by, zk) = f(bndry->x - 2*bndry->bx, bndry->y - 2*bndry->by, zk) + 3.0*delta*val; - } - } - } + } + if(bndry->by != 0) { + for(; !bndry->isDone(); bndry->next1d()) { + // x norm is shifted by half a grid point because it is staggered. + // y norm is located half way between first grid cell and guard cell. + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) + localmesh->GlobalX(bndry->x - 1) ); + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) + localmesh->GlobalY(bndry->y - bndry->by) ); + + BoutReal delta = bndry->bx*metric->dx(bndry->x,bndry->y)+bndry->by*metric->dy(bndry->x,bndry->y); + + for(int zk=0;zkLocalNz;zk++) { + if(fg){ + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(localmesh->LocalNz),t); + } + f(bndry->x,bndry->y, zk) = f(bndry->x-bndry->bx, bndry->y-bndry->by, zk) + delta*val; + if (bndry->width == 2){ + f(bndry->x + bndry->bx, bndry->y + bndry->by, zk) = f(bndry->x - 2*bndry->bx, bndry->y - 2*bndry->by, zk) + 3.0*delta*val; + } + } } } - else if( loc == CELL_YLOW ) { - // Field is shifted in Y - - if(bndry->by > 0) { - // Outer y boundary - for(; !bndry->isDone(); bndry->next1d()) { - - BoutReal xnorm = mesh->GlobalX(bndry->x); - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) - + mesh->GlobalY(bndry->y - bndry->by) ); - for(int zk=0;zkLocalNz;zk++) { - - if(fg){ - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(mesh->LocalNz),t) * metric->dy(bndry->x, bndry->y); - } - f(bndry->x,bndry->y,zk) = (4.*f(bndry->x, bndry->y - bndry->by,zk) - f(bndry->x, bndry->y - 2*bndry->by,zk) + 2.*val)/3.; - - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - // Use third order extrapolation because boundary point is set to third order, and these points - // may be used be used by 2nd order upwinding type schemes, which require 3rd order - f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) - + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); - } - } - } + } else if( loc == CELL_YLOW ) { + // Field is shifted in Y + + if(bndry->by > 0) { + // Outer y boundary + for(; !bndry->isDone(); bndry->next1d()) { + + BoutReal xnorm = localmesh->GlobalX(bndry->x); + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) + + localmesh->GlobalY(bndry->y - bndry->by) ); + for(int zk=0;zkLocalNz;zk++) { + + if(fg){ + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(localmesh->LocalNz),t) * metric->dy(bndry->x, bndry->y); + } + f(bndry->x,bndry->y,zk) = (4.*f(bndry->x, bndry->y - bndry->by,zk) - f(bndry->x, bndry->y - 2*bndry->by,zk) + 2.*val)/3.; + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + // Use third order extrapolation because boundary point is set to third order, and these points + // may be used be used by 2nd order upwinding type schemes, which require 3rd order + f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) + + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); + } + } } - if(bndry->by < 0) { - // Inner y boundary. Set one point inwards - for(; !bndry->isDone(); bndry->next1d()) { - - BoutReal xnorm = mesh->GlobalX(bndry->x); - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) - + mesh->GlobalY(bndry->y - bndry->by) ); - for(int zk=0;zkLocalNz;zk++) { - if(fg) - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(mesh->LocalNz),t) * metric->dy(bndry->x, bndry->y - bndry->by); - - f(bndry->x,bndry->y - bndry->by,zk) = (4.*f(bndry->x, bndry->y - 2*bndry->by,zk) - f(bndry->x, bndry->y - 3*bndry->by,zk) - 2.*val)/3.; - - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=0;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - // Use third order extrapolation because boundary point is set to third order, and these points - // may be used be used by 2nd order upwinding type schemes, which require 3rd order - f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) - + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); - } - } - } + } + if(bndry->by < 0) { + // Inner y boundary. Set one point inwards + for(; !bndry->isDone(); bndry->next1d()) { + + BoutReal xnorm = localmesh->GlobalX(bndry->x); + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) + + localmesh->GlobalY(bndry->y - bndry->by) ); + for(int zk=0;zkLocalNz;zk++) { + if(fg) + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(localmesh->LocalNz),t) * metric->dy(bndry->x, bndry->y - bndry->by); + + f(bndry->x,bndry->y - bndry->by,zk) = (4.*f(bndry->x, bndry->y - 2*bndry->by,zk) - f(bndry->x, bndry->y - 3*bndry->by,zk) - 2.*val)/3.; + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=0;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + // Use third order extrapolation because boundary point is set to third order, and these points + // may be used be used by 2nd order upwinding type schemes, which require 3rd order + f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) + + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); + } + } } - if(bndry->bx !=0 ){ - // x boundaries. - for(; !bndry->isDone(); bndry->next1d()) { - // x norm is located half way between first grid cell and guard cell. - // y norm is shifted by half a grid point because it is staggered. - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) + mesh->GlobalX(bndry->x - bndry->bx) ); - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) + mesh->GlobalY(bndry->y - 1) ); - - BoutReal delta = bndry->bx*metric->dx(bndry->x,bndry->y)+bndry->by*metric->dy(bndry->x,bndry->y); - - for(int zk=0;zkLocalNz;zk++) { - if(fg){ - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(mesh->LocalNz),t); - } - f(bndry->x,bndry->y, zk) = f(bndry->x-bndry->bx, bndry->y-bndry->by, zk) + delta*val; - if (bndry->width == 2){ - f(bndry->x + bndry->bx, bndry->y + bndry->by, zk) = f(bndry->x - 2*bndry->bx, bndry->y - 2*bndry->by, zk) + 3.0*delta*val; - } - } - } + } + if(bndry->bx !=0 ){ + // x boundaries. + for(; !bndry->isDone(); bndry->next1d()) { + // x norm is located half way between first grid cell and guard cell. + // y norm is shifted by half a grid point because it is staggered. + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) + localmesh->GlobalX(bndry->x - bndry->bx) ); + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) + localmesh->GlobalY(bndry->y - 1) ); + + BoutReal delta = bndry->bx*metric->dx(bndry->x,bndry->y)+bndry->by*metric->dy(bndry->x,bndry->y); + + for(int zk=0;zkLocalNz;zk++) { + if(fg){ + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(localmesh->LocalNz),t); + } + f(bndry->x,bndry->y, zk) = f(bndry->x-bndry->bx, bndry->y-bndry->by, zk) + delta*val; + if (bndry->width == 2){ + f(bndry->x + bndry->bx, bndry->y + bndry->by, zk) = f(bndry->x - 2*bndry->bx, bndry->y - 2*bndry->by, zk) + 3.0*delta*val; + } + } } } - } - else { + } else { + // CELL_CENTRE or CELL_ZLOW for(; !bndry->isDone(); bndry->next1d()) { - // Calculate the X and Y normalised values half-way between the guard cell and grid cell - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) // In the guard cell - + mesh->GlobalX(bndry->x - bndry->bx) ); // the grid cell - - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) // In the guard cell - + mesh->GlobalY(bndry->y - bndry->by) ); // the grid cell - + // Calculate the X and Y normalised values half-way between the guard cell and grid cell + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) // In the guard cell + + localmesh->GlobalX(bndry->x - bndry->bx) ); // the grid cell + + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) // In the guard cell + + localmesh->GlobalY(bndry->y - bndry->by) ); // the grid cell + BoutReal delta = bndry->bx*metric->dx(bndry->x,bndry->y)+bndry->by*metric->dy(bndry->x,bndry->y); - - for(int zk=0;zkLocalNz;zk++) { - if(fg){ - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(mesh->LocalNz),t); - } - f(bndry->x,bndry->y, zk) = f(bndry->x-bndry->bx, bndry->y-bndry->by, zk) + delta*val; - if (bndry->width == 2){ - f(bndry->x + bndry->bx, bndry->y + bndry->by, zk) = f(bndry->x - 2*bndry->bx, bndry->y - 2*bndry->by, zk) + 3.0*delta*val; - } + + for(int zk=0;zkLocalNz;zk++) { + if(fg){ + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(localmesh->LocalNz),t); + } + f(bndry->x,bndry->y, zk) = f(bndry->x-bndry->bx, bndry->y-bndry->by, zk) + delta*val; + if (bndry->width == 2){ + f(bndry->x + bndry->bx, bndry->y + bndry->by, zk) = f(bndry->x - 2*bndry->bx, bndry->y - 2*bndry->by, zk) + 3.0*delta*val; + } } } } @@ -2098,9 +2087,10 @@ void BoundaryNeumann::apply_ddt(Field2D &f) { } void BoundaryNeumann::apply_ddt(Field3D &f) { + Mesh* localmesh = f.getMesh(); Field3D *dt = f.timeDeriv(); for(bndry->first(); !bndry->isDone(); bndry->next()) - for(int z=0;zLocalNz;z++) + for(int z=0;zLocalNz;z++) (*dt)(bndry->x,bndry->y,z) = 0.; // Set time derivative to zero } @@ -2123,6 +2113,12 @@ void BoundaryNeumann_O4::apply(Field2D &f,BoutReal t) { // Set (at 4th order) the value at the mid-point between the guard cell and the grid cell to be val // N.B. Only first guard cells (closest to the grid) should ever be used + + Mesh* localmesh = f.getMesh(); + + // Check for staggered grids + ASSERT1(f.getLocation() == CELL_CENTRE || f.getLocation() == CELL_ZLOW); + bndry->first(); // Decide which generator to use @@ -2131,43 +2127,34 @@ void BoundaryNeumann_O4::apply(Field2D &f,BoutReal t) { fg = f.getBndryGenerator(bndry->location); BoutReal val = 0.0; - - // Check for staggered grids - CELL_LOC loc = f.getLocation(); - if(mesh->StaggerGrids && loc != CELL_CENTRE) { - throw BoutException("neumann_o4 not implemented with staggered grid yet"); - } - else { - // Non-staggered, standard case - - Coordinates *coords = f.getCoordinates(); - for(bndry->first(); !bndry->isDone(); bndry->next1d()) { - BoutReal delta = bndry->bx*coords->dx(bndry->x,bndry->y)+bndry->by*coords->dy(bndry->x,bndry->y); - - if(fg) { - // Calculate the X and Y normalised values half-way between the guard cell and grid cell - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) // In the guard cell - + mesh->GlobalX(bndry->x - bndry->bx) ); // the grid cell - - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) // In the guard cell - + mesh->GlobalY(bndry->y - bndry->by) ); // the grid cell - - val = fg->generate(xnorm, TWOPI*ynorm, 0.0, t); - } - - f(bndry->x, bndry->y) = 12.*delta*val/11. - + - ( - + 17.*f(bndry->x- bndry->bx, bndry->y- bndry->by) - + 9.*f(bndry->x-2*bndry->bx, bndry->y-2*bndry->by) - - 5.*f(bndry->x-3*bndry->bx, bndry->y-3*bndry->by) - + f(bndry->x-4*bndry->bx, bndry->y-4*bndry->by) - )/22.; + Coordinates *coords = f.getCoordinates(); - if (bndry->width == 2){ - throw BoutException("neumann_o4 with a boundary width of 2 not implemented yet"); - } + for(bndry->first(); !bndry->isDone(); bndry->next1d()) { + BoutReal delta = bndry->bx*coords->dx(bndry->x,bndry->y)+bndry->by*coords->dy(bndry->x,bndry->y); + + if(fg) { + // Calculate the X and Y normalised values half-way between the guard cell and grid cell + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) // In the guard cell + + localmesh->GlobalX(bndry->x - bndry->bx) ); // the grid cell + + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) // In the guard cell + + localmesh->GlobalY(bndry->y - bndry->by) ); // the grid cell + + val = fg->generate(xnorm, TWOPI*ynorm, 0.0, t); + } + + f(bndry->x, bndry->y) = 12.*delta*val/11. + + + ( + + 17.*f(bndry->x- bndry->bx, bndry->y- bndry->by) + + 9.*f(bndry->x-2*bndry->bx, bndry->y-2*bndry->by) + - 5.*f(bndry->x-3*bndry->bx, bndry->y-3*bndry->by) + + f(bndry->x-4*bndry->bx, bndry->y-4*bndry->by) + )/22.; + + if (bndry->width == 2){ + throw BoutException("neumann_o4 with a boundary width of 2 not implemented yet"); } } } @@ -2177,6 +2164,11 @@ void BoundaryNeumann_O4::apply(Field3D &f) { } void BoundaryNeumann_O4::apply(Field3D &f,BoutReal t) { + Mesh* localmesh = f.getMesh(); + + // Check for staggered grids + ASSERT1(f.getLocation() == CELL_CENTRE || f.getLocation() == CELL_ZLOW); + bndry->first(); // Decide which generator to use @@ -2185,41 +2177,34 @@ void BoundaryNeumann_O4::apply(Field3D &f,BoutReal t) { fg = f.getBndryGenerator(bndry->location); BoutReal val = 0.0; - - // Check for staggered grids - CELL_LOC loc = f.getLocation(); - if(mesh->StaggerGrids && loc != CELL_CENTRE) { - throw BoutException("neumann_o4 not implemented with staggered grid yet"); - } - else { - Coordinates *coords = f.getCoordinates(); - for(; !bndry->isDone(); bndry->next1d()) { - // Calculate the X and Y normalised values half-way between the guard cell and grid cell - BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) // In the guard cell - + mesh->GlobalX(bndry->x - bndry->bx) ); // the grid cell - BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) // In the guard cell - + mesh->GlobalY(bndry->y - bndry->by) ); // the grid cell - - BoutReal delta = bndry->bx*coords->dx(bndry->x,bndry->y)+bndry->by*coords->dy(bndry->x,bndry->y); + Coordinates *coords = f.getCoordinates(); + for(; !bndry->isDone(); bndry->next1d()) { + // Calculate the X and Y normalised values half-way between the guard cell and grid cell + BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) // In the guard cell + + localmesh->GlobalX(bndry->x - bndry->bx) ); // the grid cell - for(int zk=0;zkLocalNz;zk++) { - if(fg){ - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(mesh->LocalNz),t); - } + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) // In the guard cell + + localmesh->GlobalY(bndry->y - bndry->by) ); // the grid cell - f(bndry->x,bndry->y, zk) = 12.*delta*val/11. - + - ( - + 17.*f(bndry->x- bndry->bx, bndry->y- bndry->by, zk) - + 9.*f(bndry->x-2*bndry->bx, bndry->y-2*bndry->by, zk) - - 5.*f(bndry->x-3*bndry->bx, bndry->y-3*bndry->by, zk) - + f(bndry->x-4*bndry->bx, bndry->y-4*bndry->by, zk) - )/22.; + BoutReal delta = bndry->bx*coords->dx(bndry->x,bndry->y)+bndry->by*coords->dy(bndry->x,bndry->y); - if (bndry->width == 2){ - throw BoutException("neumann_o4 with a boundary width of 2 not implemented yet"); - } + for(int zk=0;zkLocalNz;zk++) { + if(fg){ + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(localmesh->LocalNz),t); + } + + f(bndry->x,bndry->y, zk) = 12.*delta*val/11. + + + ( + + 17.*f(bndry->x- bndry->bx, bndry->y- bndry->by, zk) + + 9.*f(bndry->x-2*bndry->bx, bndry->y-2*bndry->by, zk) + - 5.*f(bndry->x-3*bndry->bx, bndry->y-3*bndry->by, zk) + + f(bndry->x-4*bndry->bx, bndry->y-4*bndry->by, zk) + )/22.; + + if (bndry->width == 2){ + throw BoutException("neumann_o4 with a boundary width of 2 not implemented yet"); } } } @@ -2232,16 +2217,17 @@ void BoundaryNeumann_O4::apply_ddt(Field2D &f) { } void BoundaryNeumann_O4::apply_ddt(Field3D &f) { + Mesh* localmesh = f.getMesh(); Field3D *dt = f.timeDeriv(); for(bndry->first(); !bndry->isDone(); bndry->next()) - for(int z=0;zLocalNz;z++) + for(int z=0;zLocalNz;z++) (*dt)(bndry->x,bndry->y,z) = 0.; // Set time derivative to zero } /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryNeumann_4thOrder::clone(BoundaryRegion *region, const list &args) { - verifyNumPoints(region,4); + verifyNumPoints(region, 4); if(!args.empty()) { // First argument should be a value val = stringToReal(args.front()); @@ -2262,11 +2248,12 @@ void BoundaryNeumann_4thOrder::apply(Field2D &f) { } void BoundaryNeumann_4thOrder::apply(Field3D &f) { + Mesh* localmesh = f.getMesh(); Coordinates *metric = f.getCoordinates(); // Set (at 4th order) the gradient at the mid-point between the guard cell and the grid cell to be val // This sets the value of the co-ordinate derivative, i.e. DDX/DDY not Grad_par/Grad_perp.x for(bndry->first(); !bndry->isDone(); bndry->next1d()) - for(int z=0;zLocalNz;z++) { + for(int z=0;zLocalNz;z++) { BoutReal delta = -(bndry->bx*metric->dx(bndry->x,bndry->y)+bndry->by*metric->dy(bndry->x,bndry->y)); f(bndry->x,bndry->y,z) = 12.*delta/11.*val + 17./22.*f(bndry->x-bndry->bx,bndry->y-bndry->by,z) + 9./22.*f(bndry->x-2*bndry->bx,bndry->y-2*bndry->by,z) - 5./22.*f(bndry->x-3*bndry->bx,bndry->y-3*bndry->by,z) + 1./22.*f(bndry->x-4*bndry->bx,bndry->y-4*bndry->by,z); f(bndry->x+bndry->bx,bndry->y+bndry->by,z) = -24.*delta*val + 27.*f(bndry->x,bndry->y,z) - 27.*f(bndry->x-bndry->bx,bndry->y-bndry->by,z) + f(bndry->x-2*bndry->bx,bndry->y-2*bndry->by,z); // The f(bndry->x-4*bndry->bx,bndry->y-4*bndry->by,z) term vanishes, so that this sets to zero the 4th order central difference first derivative at the point half way between the guard cell and the grid cell @@ -2280,16 +2267,17 @@ void BoundaryNeumann_4thOrder::apply_ddt(Field2D &f) { } void BoundaryNeumann_4thOrder::apply_ddt(Field3D &f) { + Mesh* localmesh = f.getMesh(); Field3D *dt = f.timeDeriv(); for(bndry->first(); !bndry->isDone(); bndry->next()) - for(int z=0;zLocalNz;z++) + for(int z=0;zLocalNz;z++) (*dt)(bndry->x,bndry->y,z) = 0.; // Set time derivative to zero } /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryNeumannPar::clone(BoundaryRegion *region, const list &args) { - verifyNumPoints(region,1); + verifyNumPoints(region, 1); if(!args.empty()) { output << "WARNING: Ignoring arguments to BoundaryNeumann2\n"; } @@ -2305,16 +2293,17 @@ void BoundaryNeumannPar::apply(Field2D &f) { } void BoundaryNeumannPar::apply(Field3D &f) { + Mesh* localmesh = f.getMesh(); Coordinates *metric = f.getCoordinates(); for(bndry->first(); !bndry->isDone(); bndry->next()) - for(int z=0;zLocalNz;z++) + for(int z=0;zLocalNz;z++) f(bndry->x,bndry->y,z) = f(bndry->x - bndry->bx,bndry->y - bndry->by,z)*sqrt(metric->g_22(bndry->x, bndry->y)/metric->g_22(bndry->x - bndry->bx, bndry->y - bndry->by)); } /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryRobin::clone(BoundaryRegion *region, const list &args) { - verifyNumPoints(region,1); + verifyNumPoints(region, 1); BoutReal a = 0.5, b = 1.0, g = 0.; list::const_iterator it = args.begin(); @@ -2358,16 +2347,17 @@ void BoundaryRobin::apply(Field2D &f) { } void BoundaryRobin::apply(Field3D &f) { + Mesh* localmesh = f.getMesh(); if(fabs(bval) < 1.e-12) { for(bndry->first(); !bndry->isDone(); bndry->next()) - for(int z=0;zLocalNz;z++) + for(int z=0;zLocalNz;z++) f(bndry->x, bndry->y, z) = gval / aval; }else { BoutReal sign = 1.; if( (bndry->bx < 0) || (bndry->by < 0)) sign = -1.; for(bndry->first(); !bndry->isDone(); bndry->next()) - for(int z=0;zLocalNz;z++) + for(int z=0;zLocalNz;z++) f(bndry->x, bndry->y, z) = f(bndry->x - bndry->bx, bndry->y - bndry->by, z) + sign*(gval - aval*f(bndry->x - bndry->bx, bndry->y - bndry->by, z) ) / bval; } } @@ -2381,15 +2371,16 @@ void BoundaryConstGradient::apply(Field2D &f){ } void BoundaryConstGradient::apply(Field3D &f) { + Mesh* localmesh = f.getMesh(); for(bndry->first(); !bndry->isDone(); bndry->next()) - for(int z=0;zLocalNz;z++) + for(int z=0;zLocalNz;z++) f(bndry->x, bndry->y, z) = 2.*f(bndry->x - bndry->bx, bndry->y - bndry->by, z) - f(bndry->x - 2*bndry->bx,bndry->y - 2*bndry->by,z); } /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryConstGradient::clone(BoundaryRegion *region, const list &args) { - verifyNumPoints(region,2); + verifyNumPoints(region, 2); if(!args.empty()) { output << "WARNING: Ignoring arguments to BoundaryConstGradient\n"; } @@ -2399,7 +2390,7 @@ BoundaryOp* BoundaryConstGradient::clone(BoundaryRegion *region, const list &args) { - verifyNumPoints(region,2); + verifyNumPoints(region, 2); if(!args.empty()) { output << "WARNING: Ignoring arguments to BoundaryZeroLaplace\n"; } @@ -2429,7 +2420,9 @@ void BoundaryZeroLaplace::apply(Field2D &f) { } void BoundaryZeroLaplace::apply(Field3D &f) { - int ncz = mesh->LocalNz; + Mesh* localmesh = f.getMesh(); + + int ncz = localmesh->LocalNz; Coordinates *metric = f.getCoordinates(); @@ -2452,8 +2445,8 @@ void BoundaryZeroLaplace::apply(Field3D &f) { int y = bndry->y; // Take FFT of last 2 points in domain - rfft(f(x - bx, y), mesh->LocalNz, c0.begin()); - rfft(f(x - 2 * bx, y), mesh->LocalNz, c1.begin()); + rfft(f(x - bx, y), localmesh->LocalNz, c0.begin()); + rfft(f(x - 2 * bx, y), localmesh->LocalNz, c1.begin()); c1[0] = c0[0] - c1[0]; // Only need gradient // Solve metric->g11*d2f/dx2 - metric->g33*kz^2f = 0 @@ -2472,7 +2465,7 @@ void BoundaryZeroLaplace::apply(Field3D &f) { c0[jz] *= exp(coef * kwave); // The decaying solution only } // Reverse FFT - irfft(c0.begin(), mesh->LocalNz, f(x, y)); + irfft(c0.begin(), localmesh->LocalNz, f(x, y)); bndry->nextX(); x = bndry->x; @@ -2485,7 +2478,7 @@ void BoundaryZeroLaplace::apply(Field3D &f) { BoundaryOp *BoundaryZeroLaplace2::clone(BoundaryRegion *region, const list &args) { - verifyNumPoints(region, 3); + verifyNumPoints(region, 3); if (!args.empty()) { output << "WARNING: Ignoring arguments to BoundaryZeroLaplace2\n"; } @@ -2519,7 +2512,9 @@ void BoundaryZeroLaplace2::apply(Field2D &f) { } void BoundaryZeroLaplace2::apply(Field3D &f) { - int ncz = mesh->LocalNz; + Mesh* localmesh = f.getMesh(); + + int ncz = localmesh->LocalNz; ASSERT0(ncz % 2 == 0); // Allocation assumes even number @@ -2572,7 +2567,7 @@ void BoundaryZeroLaplace2::apply(Field3D &f) { /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryConstLaplace::clone(BoundaryRegion *region, const list &args) { - verifyNumPoints(region,2); + verifyNumPoints(region, 2); if(!args.empty()) { output << "WARNING: Ignoring arguments to BoundaryConstLaplace\n"; } @@ -2615,9 +2610,11 @@ void BoundaryConstLaplace::apply(Field3D &f) { throw BoutException("ERROR: Can't apply Zero Laplace condition to non-X boundaries\n"); } + Mesh* localmesh = f.getMesh(); + Coordinates *metric = f.getCoordinates(); - int ncz = mesh->LocalNz; + int ncz = localmesh->LocalNz; // Allocate memory Array c0(ncz/2 + 1), c1(ncz/2 + 1), c2(ncz/2 + 1); @@ -2686,21 +2683,23 @@ void BoundaryDivCurl::apply(Vector3D &var) { int jx, jy, jz, jzp, jzm; BoutReal tmp; - Coordinates *metric = mesh->coordinates(var.getLocation()); + Mesh* localmesh = var.x.getMesh(); + + Coordinates *metric = localmesh->getCoordinates(var.getLocation()); - int ncz = mesh->LocalNz; + int ncz = localmesh->LocalNz; if(bndry->location != BNDRY_XOUT) { throw BoutException("ERROR: DivCurl boundary only works for outer X currently\n"); } var.toCovariant(); - if(mesh->xstart > 2) { + if(localmesh->xstart > 2) { throw BoutException("Error: Div = Curl = 0 boundary condition doesn't work for MXG > 2. Sorry\n"); } - jx = mesh->xend+1; - for(jy=1;jyLocalNy-1;jy++) { + jx = localmesh->xend+1; + for(jy=1;jyLocalNy-1;jy++) { for(jz=0;jzdy(jx-1,jy-1) + metric->dy(jx-1,jy)); var.y(jx,jy,jz) = var.y(jx-2,jy,jz) + (metric->dx(jx-2,jy) + metric->dx(jx-1,jy)) * tmp; - if(mesh->xstart == 2) + if(localmesh->xstart == 2) // 4th order to get last point var.y(jx+1,jy,jz) = var.y(jx-3,jy,jz) + 4.*metric->dx(jx,jy)*tmp; @@ -2720,7 +2719,7 @@ void BoundaryDivCurl::apply(Vector3D &var) { tmp = (var.x(jx-1,jy,jzp) - var.x(jx-1,jy,jzm)) / (2.*metric->dz); var.z(jx,jy,jz) = var.z(jx-2,jy,jz) + (metric->dx(jx-2,jy) + metric->dx(jx-1,jy)) * tmp; - if(mesh->xstart == 2) + if(localmesh->xstart == 2) 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) @@ -2739,7 +2738,7 @@ void BoundaryDivCurl::apply(Vector3D &var) { var.x(jx,jy,jz) = ( metric->J(jx-2,jy)*metric->g11(jx-2,jy)*var.x(jx-2,jy,jz) + (metric->dx(jx-2,jy) + metric->dx(jx-1,jy)) * tmp ) / metric->J(jx,jy)*metric->g11(jx,jy); - if(mesh->xstart == 2) + if(localmesh->xstart == 2) var.x(jx+1,jy,jz) = ( metric->J(jx-3,jy)*metric->g11(jx-3,jy)*var.x(jx-3,jy,jz) + 4.*metric->dx(jx,jy)*tmp ) / metric->J(jx+1,jy)*metric->g11(jx+1,jy); } @@ -2780,7 +2779,7 @@ void BoundaryFree::apply_ddt(Field3D &UNUSED(f)) { // 2nd order extrapolation: BoundaryOp* BoundaryFree_O2::clone(BoundaryRegion *region, const list &args){ - verifyNumPoints(region,2); + verifyNumPoints(region, 2); if(!args.empty()) { output << "WARNING: Ignoring arguments to BoundaryFree\n"; } @@ -2790,211 +2789,205 @@ BoundaryOp* BoundaryFree_O2::clone(BoundaryRegion *region, const list &a void BoundaryFree_O2::apply(Field2D &f) { // Set (at 2nd order) the value at the mid-point between the guard cell and the grid cell to be val // N.B. Only first guard cells (closest to the grid) should ever be used - - bndry->first(); + + Mesh* localmesh = f.getMesh(); // Check for staggered grids - CELL_LOC loc = f.getLocation(); - if(mesh->StaggerGrids && loc != CELL_CENTRE) { - // Staggered. Need to apply slightly differently - - if( loc == CELL_XLOW) { - // Field is shifted in X - - if(bndry->bx > 0) { - // Outer x boundary - for(; !bndry->isDone(); bndry->next1d()) { - for(int i=0;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi) = 2*f(xi - bndry->bx, yi -bndry->by) - f(xi- 2*bndry->bx, yi - 2*bndry->by); - } - } + ASSERT1(localmesh->StaggerGrids || loc == CELL_CENTRE); + + bndry->first(); + + // If staggered, need to apply slightly differently + if( loc == CELL_XLOW) { + // Field is shifted in X + + if(bndry->bx > 0) { + // Outer x boundary + for(; !bndry->isDone(); bndry->next1d()) { + for(int i=0;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi) = 2*f(xi - bndry->bx, yi -bndry->by) - f(xi- 2*bndry->bx, yi - 2*bndry->by); + } } - if(bndry->bx < 0) { - // Inner x boundary. Set one point inwards - for(; !bndry->isDone(); bndry->next1d()) { - for(int i=-1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi) = 2*f(xi - bndry->bx, yi -bndry->by) - f(xi- 2*bndry->bx, yi - 2*bndry->by); - } - } + } + if(bndry->bx < 0) { + // Inner x boundary. Set one point inwards + for(; !bndry->isDone(); bndry->next1d()) { + for(int i=-1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi) = 2*f(xi - bndry->bx, yi -bndry->by) - f(xi- 2*bndry->bx, yi - 2*bndry->by); + } } - if(bndry->by != 0){ - // y boundaries - for(; !bndry->isDone(); bndry->next1d()) { - for(int i=0;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi) = 2*f(xi - bndry->bx, yi -bndry->by) - f(xi- 2*bndry->bx, yi - 2*bndry->by); - } - - } + } + if(bndry->by != 0){ + // y boundaries + for(; !bndry->isDone(); bndry->next1d()) { + for(int i=0;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi) = 2*f(xi - bndry->bx, yi -bndry->by) - f(xi- 2*bndry->bx, yi - 2*bndry->by); + } + } } - else if( loc == CELL_YLOW ) { - // Field is shifted in Y - - if(bndry->by > 0) { - // Upper y boundary - - for(; !bndry->isDone(); bndry->next1d()) { - for(int i=0;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi) = 2*f(xi - bndry->bx, yi -bndry->by) - f(xi- 2*bndry->bx, yi - 2*bndry->by); - } - } + } else if( loc == CELL_YLOW ) { + // Field is shifted in Y + + if(bndry->by > 0) { + // Upper y boundary + + for(; !bndry->isDone(); bndry->next1d()) { + for(int i=0;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi) = 2*f(xi - bndry->bx, yi -bndry->by) - f(xi- 2*bndry->bx, yi - 2*bndry->by); + } } - if(bndry->by < 0) { - // Lower y boundary. Set one point inwards - for(; !bndry->isDone(); bndry->next1d()) { - for(int i=-1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi) = 2*f(xi - bndry->bx, yi -bndry->by) - f(xi- 2*bndry->bx, yi - 2*bndry->by); - } - } + } + if(bndry->by < 0) { + // Lower y boundary. Set one point inwards + for(; !bndry->isDone(); bndry->next1d()) { + for(int i=-1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi) = 2*f(xi - bndry->bx, yi -bndry->by) - f(xi- 2*bndry->bx, yi - 2*bndry->by); + } } - if(bndry->bx != 0){ - // x boundaries - for(; !bndry->isDone(); bndry->next1d()) { - - for(int i=0;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi) = 2*f(xi - bndry->bx, yi -bndry->by) - f(xi- 2*bndry->bx, yi - 2*bndry->by); - } - } + } + if(bndry->bx != 0){ + // x boundaries + for(; !bndry->isDone(); bndry->next1d()) { + + for(int i=0;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi) = 2*f(xi - bndry->bx, yi -bndry->by) - f(xi- 2*bndry->bx, yi - 2*bndry->by); + } } } - } - else { - // Non-staggered, standard case - + } else { + // CELL_CENTRE or CELL_ZLOW for(; !bndry->isDone(); bndry->next1d()) { - + for(int i=0;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi) = 2*f(xi - bndry->bx, yi -bndry->by) - f(xi- 2*bndry->bx, yi - 2*bndry->by); - } + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi) = 2*f(xi - bndry->bx, yi -bndry->by) - f(xi- 2*bndry->bx, yi - 2*bndry->by); + } } } } void BoundaryFree_O2::apply(Field3D &f) { - // Extrapolate from the last evolved simulation cells into the guard cells at 3rd order. - - bndry->first(); + // Extrapolate from the last evolved simulation cells into the guard cells at 3rd order. + Mesh* localmesh = f.getMesh(); // Check for staggered grids - CELL_LOC loc = f.getLocation(); - if(mesh->StaggerGrids && loc != CELL_CENTRE) { - // Staggered. Need to apply slightly differently - - if( loc == CELL_XLOW ) { - // Field is shifted in X - - if(bndry->bx > 0) { - // Outer x boundary - - for(; !bndry->isDone(); bndry->next1d()) { - - for(int zk=0;zkLocalNz;zk++) { - for(int i=0;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi, zk) = 2*f(xi - bndry->bx, yi -bndry->by, zk) - f(xi- 2*bndry->bx, yi - 2*bndry->by, zk); - } - } - } + ASSERT1(localmesh->StaggerGrids || loc == CELL_CENTRE); + + bndry->first(); + + // If staggered, need to apply slightly differently + if( loc == CELL_XLOW ) { + // Field is shifted in X + + if(bndry->bx > 0) { + // Outer x boundary + + for(; !bndry->isDone(); bndry->next1d()) { + + for(int zk=0;zkLocalNz;zk++) { + for(int i=0;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi, zk) = 2*f(xi - bndry->bx, yi -bndry->by, zk) - f(xi- 2*bndry->bx, yi - 2*bndry->by, zk); + } + } } - if(bndry->bx < 0) { - // Inner x boundary. Set one point inwards - for(; !bndry->isDone(); bndry->next1d()) { - - for(int zk=0;zkLocalNz;zk++) { - for(int i=-1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi, zk) = 2*f(xi - bndry->bx, yi -bndry->by, zk) - f(xi- 2*bndry->bx, yi - 2*bndry->by, zk); - } - } - } + } + if(bndry->bx < 0) { + // Inner x boundary. Set one point inwards + for(; !bndry->isDone(); bndry->next1d()) { + + for(int zk=0;zkLocalNz;zk++) { + for(int i=-1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi, zk) = 2*f(xi - bndry->bx, yi -bndry->by, zk) - f(xi- 2*bndry->bx, yi - 2*bndry->by, zk); + } + } } - if(bndry->by != 0){ - //y boundaries - - for(; !bndry->isDone(); bndry->next1d()) { - - for(int zk=0;zkLocalNz;zk++) { - for(int i=0;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi, zk) = 2*f(xi - bndry->bx, yi -bndry->by, zk) - f(xi- 2*bndry->bx, yi - 2*bndry->by, zk); - } - } - } + } + if(bndry->by != 0){ + //y boundaries + + for(; !bndry->isDone(); bndry->next1d()) { + + for(int zk=0;zkLocalNz;zk++) { + for(int i=0;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi, zk) = 2*f(xi - bndry->bx, yi -bndry->by, zk) - f(xi- 2*bndry->bx, yi - 2*bndry->by, zk); + } + } } } - else if( loc == CELL_YLOW ) { - // Field is shifted in Y - - if(bndry->by > 0) { - // Upper y boundary - for(; !bndry->isDone(); bndry->next1d()) { - for(int zk=0;zkLocalNz;zk++) { - for(int i=0;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi, zk) = 2*f(xi - bndry->bx, yi -bndry->by, zk) - f(xi- 2*bndry->bx, yi - 2*bndry->by, zk); - } - } - } + } else if( loc == CELL_YLOW ) { + // Field is shifted in Y + + if(bndry->by > 0) { + // Upper y boundary + for(; !bndry->isDone(); bndry->next1d()) { + for(int zk=0;zkLocalNz;zk++) { + for(int i=0;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi, zk) = 2*f(xi - bndry->bx, yi -bndry->by, zk) - f(xi- 2*bndry->bx, yi - 2*bndry->by, zk); + } + } } - if(bndry->by < 0) { - // Lower y boundary. Set one point inwards - for(; !bndry->isDone(); bndry->next1d()) { - - for(int zk=0;zkLocalNz;zk++) { - for(int i=-1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi, zk) = 2*f(xi - bndry->bx, yi -bndry->by, zk) - f(xi- 2*bndry->bx, yi - 2*bndry->by, zk); - } - } - } + } + if(bndry->by < 0) { + // Lower y boundary. Set one point inwards + for(; !bndry->isDone(); bndry->next1d()) { + + for(int zk=0;zkLocalNz;zk++) { + for(int i=-1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi, zk) = 2*f(xi - bndry->bx, yi -bndry->by, zk) - f(xi- 2*bndry->bx, yi - 2*bndry->by, zk); + } + } } - if(bndry->bx != 0){ - // x boundaries - for(; !bndry->isDone(); bndry->next1d()) { - - for(int zk=0;zkLocalNz;zk++) { - for(int i=0;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi, zk) = 2*f(xi - bndry->bx, yi -bndry->by, zk) - f(xi- 2*bndry->bx, yi - 2*bndry->by, zk); - } - } - } + } + if(bndry->bx != 0){ + // x boundaries + for(; !bndry->isDone(); bndry->next1d()) { + + for(int zk=0;zkLocalNz;zk++) { + for(int i=0;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi, zk) = 2*f(xi - bndry->bx, yi -bndry->by, zk) - f(xi- 2*bndry->bx, yi - 2*bndry->by, zk); + } + } } } - } - else { - // Standard (non-staggered) case + } else { + // CELL_CENTRE or CELL_ZLOW for(; !bndry->isDone(); bndry->next1d()) { - - for(int zk=0;zkLocalNz;zk++) { - for(int i=0;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi, zk) = 2*f(xi - bndry->bx, yi -bndry->by, zk) - f(xi- 2*bndry->bx, yi - 2*bndry->by, zk); - } + + for(int zk=0;zkLocalNz;zk++) { + for(int i=0;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi, zk) = 2*f(xi - bndry->bx, yi -bndry->by, zk) - f(xi- 2*bndry->bx, yi - 2*bndry->by, zk); + } } } } @@ -3007,9 +3000,10 @@ void BoundaryFree_O2::apply_ddt(Field2D &f) { } void BoundaryFree_O2::apply_ddt(Field3D &f) { + Mesh* localmesh = f.getMesh(); Field3D *dt = f.timeDeriv(); for(bndry->first(); !bndry->isDone(); bndry->next()) - for(int z=0;zLocalNz;z++) + for(int z=0;zLocalNz;z++) (*dt)(bndry->x,bndry->y,z) = 0.; // Set time derivative to zero } @@ -3018,7 +3012,7 @@ void BoundaryFree_O2::apply_ddt(Field3D &f) { // Third order extrapolation: ////////////////////////////////// BoundaryOp* BoundaryFree_O3::clone(BoundaryRegion *region, const list &args){ - verifyNumPoints(region,3); + verifyNumPoints(region, 3); if(!args.empty()) { output << "WARNING: Ignoring arguments to BoundaryConstLaplace\n"; @@ -3028,219 +3022,213 @@ BoundaryOp* BoundaryFree_O3::clone(BoundaryRegion *region, const list &a void BoundaryFree_O3::apply(Field2D &f) { - bndry->first(); + Mesh* localmesh = f.getMesh(); // Check for staggered grids - CELL_LOC loc = f.getLocation(); - if(mesh->StaggerGrids && loc != CELL_CENTRE) { - // Staggered. Need to apply slightly differently - - if( loc == CELL_XLOW) { - // Field is shifted in X - - if(bndry->bx > 0) { - // Outer x boundary - for(; !bndry->isDone(); bndry->next1d()) { - for(int i=0;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); - } - } + ASSERT1(localmesh->StaggerGrids || loc == CELL_CENTRE); + + bndry->first(); + + // If staggered, need to apply slightly differently + if( loc == CELL_XLOW) { + // Field is shifted in X + + if(bndry->bx > 0) { + // Outer x boundary + for(; !bndry->isDone(); bndry->next1d()) { + for(int i=0;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); + } } - if(bndry->bx < 0) { - // Inner x boundary. Set one point inwards - for(; !bndry->isDone(); bndry->next1d()) { - for(int i=-1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); - } - } + } + if(bndry->bx < 0) { + // Inner x boundary. Set one point inwards + for(; !bndry->isDone(); bndry->next1d()) { + for(int i=-1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); + } } - if(bndry->by != 0){ - // y boundaries - for(; !bndry->isDone(); bndry->next1d()) { - for(int i=0;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); - } - - } + } + if(bndry->by != 0){ + // y boundaries + for(; !bndry->isDone(); bndry->next1d()) { + for(int i=0;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); + } + } } - else if( loc == CELL_YLOW ) { - // Field is shifted in Y - - if(bndry->by > 0) { - // Upper y boundary - - for(; !bndry->isDone(); bndry->next1d()) { - for(int i=0;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); - } - } + } else if( loc == CELL_YLOW ) { + // Field is shifted in Y + + if(bndry->by > 0) { + // Upper y boundary + + for(; !bndry->isDone(); bndry->next1d()) { + for(int i=0;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); + } } - if(bndry->by < 0) { - // Lower y boundary. Set one point inwards - for(; !bndry->isDone(); bndry->next1d()) { - for(int i=-1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); - } + } + if(bndry->by < 0) { + // Lower y boundary. Set one point inwards + for(; !bndry->isDone(); bndry->next1d()) { + for(int i=-1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); + } - } } - if(bndry->bx != 0){ - // x boundaries - for(; !bndry->isDone(); bndry->next1d()) { - - for(int i=0;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); - } - } + } + if(bndry->bx != 0){ + // x boundaries + for(; !bndry->isDone(); bndry->next1d()) { + + for(int i=0;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); + } } } - } - else { - // Non-staggered, standard case - + } else { + // CELL_CENTRE or CELL_ZLOW for(; !bndry->isDone(); bndry->next1d()) { - + for(int i=0;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); - } + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi) = 3.0*f(xi - bndry->bx, yi - bndry->by) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by) + f(xi - 3*bndry->bx, yi - 3*bndry->by); + } } } } void BoundaryFree_O3::apply(Field3D &f) { - // Extrapolate from the last evolved simulation cells into the guard cells at 3rd order. - - bndry->first(); + // Extrapolate from the last evolved simulation cells into the guard cells at 3rd order. + Mesh* localmesh = f.getMesh(); // Check for staggered grids - CELL_LOC loc = f.getLocation(); - if(mesh->StaggerGrids && loc != CELL_CENTRE) { - // Staggered. Need to apply slightly differently - - if( loc == CELL_XLOW ) { - // Field is shifted in X - - if(bndry->bx > 0) { - // Outer x boundary - - for(; !bndry->isDone(); bndry->next1d()) { - - for(int zk=0;zkLocalNz;zk++) { - for(int i=0;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) - + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); - } - } - } + ASSERT1(localmesh->StaggerGrids || loc == CELL_CENTRE); + + bndry->first(); + + // If staggered, need to apply slightly differently + if( loc == CELL_XLOW ) { + // Field is shifted in X + + if(bndry->bx > 0) { + // Outer x boundary + + for(; !bndry->isDone(); bndry->next1d()) { + + for(int zk=0;zkLocalNz;zk++) { + for(int i=0;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) + + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); + } + } } - if(bndry->bx < 0) { - // Inner x boundary. Set one point inwards - for(; !bndry->isDone(); bndry->next1d()) { - - for(int zk=0;zkLocalNz;zk++) { - for(int i=-1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) - + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); - } - } - } + } + if(bndry->bx < 0) { + // Inner x boundary. Set one point inwards + for(; !bndry->isDone(); bndry->next1d()) { + + for(int zk=0;zkLocalNz;zk++) { + for(int i=-1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) + + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); + } + } } - if(bndry->by != 0){ - //y boundaries - - for(; !bndry->isDone(); bndry->next1d()) { - - for(int zk=0;zkLocalNz;zk++) { - for(int i=0;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) - + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); - } - } - } + } + if(bndry->by != 0){ + //y boundaries + + for(; !bndry->isDone(); bndry->next1d()) { + + for(int zk=0;zkLocalNz;zk++) { + for(int i=0;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) + + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); + } + } } } - else if( loc == CELL_YLOW ) { - // Field is shifted in Y - - if(bndry->by > 0) { - // Upper y boundary - for(; !bndry->isDone(); bndry->next1d()) { - for(int zk=0;zkLocalNz;zk++) { - for(int i=0;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) - + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); - } - } - } + } else if( loc == CELL_YLOW ) { + // Field is shifted in Y + + if(bndry->by > 0) { + // Upper y boundary + for(; !bndry->isDone(); bndry->next1d()) { + for(int zk=0;zkLocalNz;zk++) { + for(int i=0;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) + + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); + } + } } - if(bndry->by < 0) { - // Lower y boundary. Set one point inwards - for(; !bndry->isDone(); bndry->next1d()) { - - for(int zk=0;zkLocalNz;zk++) { - for(int i=-1;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) - + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); - } - } - } + } + if(bndry->by < 0) { + // Lower y boundary. Set one point inwards + for(; !bndry->isDone(); bndry->next1d()) { + + for(int zk=0;zkLocalNz;zk++) { + for(int i=-1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) + + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); + } + } } - if(bndry->bx != 0){ - // x boundaries - for(; !bndry->isDone(); bndry->next1d()) { - - for(int zk=0;zkLocalNz;zk++) { - for(int i=0;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) - + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); - } - - } - } + } + if(bndry->bx != 0){ + // x boundaries + for(; !bndry->isDone(); bndry->next1d()) { + + for(int zk=0;zkLocalNz;zk++) { + for(int i=0;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) + + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); + } + + } } } - } - else { - // Standard (non-staggered) case + } else { + // CELL_CENTRE or CELL_ZLOW for(; !bndry->isDone(); bndry->next1d()) { - - for(int zk=0;zkLocalNz;zk++) { - for(int i=0;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) - + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); - } + + for(int zk=0;zkLocalNz;zk++) { + for(int i=0;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) + + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); + } } } } @@ -3253,9 +3241,10 @@ void BoundaryFree_O3::apply_ddt(Field2D &f) { } void BoundaryFree_O3::apply_ddt(Field3D &f) { + Mesh* localmesh = f.getMesh(); Field3D *dt = f.timeDeriv(); for(bndry->first(); !bndry->isDone(); bndry->next()) - for(int z=0;zLocalNz;z++) + for(int z=0;zLocalNz;z++) (*dt)(bndry->x,bndry->y,z) = 0.; // Set time derivative to zero } @@ -3304,13 +3293,15 @@ void BoundaryRelax::apply_ddt(Field2D &f) { void BoundaryRelax::apply_ddt(Field3D &f) { TRACE("BoundaryRelax::apply_ddt(Field3D)"); + Mesh* localmesh = f.getMesh(); + // Make a copy of f Field3D g = f; // NOTE: This is not very efficient... copying entire field // Apply the boundary to g op->apply(g); // Set time-derivatives for(bndry->first(); !bndry->isDone(); bndry->next()) - for(int z=0;zLocalNz;z++) { + for(int z=0;zLocalNz;z++) { ddt(f)(bndry->x, bndry->y, z) = r * (g(bndry->x, bndry->y, z) - f(bndry->x, bndry->y, z)); } } @@ -3377,14 +3368,16 @@ void BoundaryToFieldAligned::apply(Field2D &f, BoutReal t) { } void BoundaryToFieldAligned::apply(Field3D &f, BoutReal t) { + Mesh* localmesh = f.getMesh(); + //NOTE: This is not very efficient... updating entire field - f = mesh->fromFieldAligned(f); + f = localmesh->fromFieldAligned(f); // Apply the boundary to shifted field op->apply(f, t); //Shift back - f = mesh->toFieldAligned(f); + f = localmesh->toFieldAligned(f); //This is inefficient -- could instead use the shiftZ just in the bndry //but this is not portable to other parallel transforms -- we could instead @@ -3396,10 +3389,12 @@ void BoundaryToFieldAligned::apply_ddt(Field2D &f) { } void BoundaryToFieldAligned::apply_ddt(Field3D &f) { - f = mesh->fromFieldAligned(f); - ddt(f) = mesh->fromFieldAligned(ddt(f)); + Mesh* localmesh = f.getMesh(); + + f = localmesh->fromFieldAligned(f); + ddt(f) = localmesh->fromFieldAligned(ddt(f)); op->apply_ddt(f); - ddt(f) = mesh->toFieldAligned(ddt(f)); + ddt(f) = localmesh->toFieldAligned(ddt(f)); } @@ -3420,14 +3415,16 @@ void BoundaryFromFieldAligned::apply(Field2D &f, BoutReal t) { } void BoundaryFromFieldAligned::apply(Field3D &f, BoutReal t) { + Mesh* localmesh = f.getMesh(); + //NOTE: This is not very efficient... shifting entire field - f = mesh->toFieldAligned(f); + f = localmesh->toFieldAligned(f); // Apply the boundary to shifted field op->apply(f, t); //Shift back - f = mesh->fromFieldAligned(f); + f = localmesh->fromFieldAligned(f); //This is inefficient -- could instead use the shiftZ just in the bndry //but this is not portable to other parallel transforms -- we could instead @@ -3439,8 +3436,10 @@ void BoundaryFromFieldAligned::apply_ddt(Field2D &f) { } void BoundaryFromFieldAligned::apply_ddt(Field3D &f) { - f = mesh->toFieldAligned(f); - ddt(f) = mesh->toFieldAligned(ddt(f)); + Mesh* localmesh = f.getMesh(); + + f = localmesh->toFieldAligned(f); + ddt(f) = localmesh->toFieldAligned(ddt(f)); op->apply_ddt(f); - ddt(f) = mesh->fromFieldAligned(ddt(f)); + ddt(f) = localmesh->fromFieldAligned(ddt(f)); } diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 10dcd9b4df..81c0e921e4 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -650,7 +650,7 @@ const Field2D Coordinates::DDZ(const Field2D &f, CELL_LOC loc, const Field2D Coordinates::Grad_par(const Field2D &var, CELL_LOC outloc, DIFF_METHOD UNUSED(method)) { TRACE("Coordinates::Grad_par( Field2D )"); - ASSERT1(location == outloc || outloc == CELL_DEFAULT); + ASSERT1(location == outloc || (outloc == CELL_DEFAULT && location == var.getLocation())); return DDY(var) / sqrt(g_22); } @@ -670,7 +670,7 @@ const Field3D Coordinates::Grad_par(const Field3D &var, CELL_LOC outloc, const Field2D Coordinates::Vpar_Grad_par(const Field2D &v, const Field2D &f, CELL_LOC outloc, DIFF_METHOD UNUSED(method)) { - ASSERT1(location == outloc || outloc == CELL_DEFAULT); + ASSERT1(location == outloc || (outloc == CELL_DEFAULT && location == f.getLocation())); return VDDY(v, f) / sqrt(g_22); } @@ -704,67 +704,61 @@ const Field3D Coordinates::Div_par(const Field3D &f, CELL_LOC outloc, // Coordinates object Field2D Bxy_floc = f.getCoordinates()->Bxy; - if (f.hasYupYdown()) { - // Need to modify yup and ydown fields - Field3D f_B = f / Bxy_floc; - if (&f.yup() == &f) { - // Identity, yup and ydown point to same field - f_B.mergeYupYdown(); - } else { - // Distinct fields - f_B.splitYupYdown(); - f_B.yup() = f.yup() / Bxy_floc; - f_B.ydown() = f.ydown() / Bxy_floc; - } - return Bxy * Grad_par(f_B, outloc, method); + if (!f.hasYupYdown()) { + // No yup/ydown fields. The Grad_par operator will + // shift to field aligned coordinates + return Bxy * Grad_par(f / Bxy_floc, outloc, method); } - // No yup/ydown fields. The Grad_par operator will - // shift to field aligned coordinates - return Bxy * Grad_par(f / Bxy_floc, outloc, method); + // Need to modify yup and ydown fields + Field3D f_B = f / Bxy_floc; + if (&f.yup() == &f) { + // Identity, yup and ydown point to same field + f_B.mergeYupYdown(); + } else { + // Distinct fields + f_B.splitYupYdown(); + f_B.yup() = f.yup() / Bxy_floc; + f_B.ydown() = f.ydown() / Bxy_floc; + } + return Bxy * Grad_par(f_B, outloc, method); } ///////////////////////////////////////////////////////// // second parallel derivative (b dot Grad)(b dot Grad) // Note: For parallel Laplacian use Laplace_par -const Field2D Coordinates::Grad2_par2(const Field2D &f, CELL_LOC outloc) { +const Field2D Coordinates::Grad2_par2(const Field2D &f, CELL_LOC outloc, DIFF_METHOD method) { TRACE("Coordinates::Grad2_par2( Field2D )"); - ASSERT1(location == outloc || outloc == CELL_DEFAULT); + ASSERT1(location == outloc || (outloc == CELL_DEFAULT && location == f.getLocation())); Field2D sg = sqrt(g_22); - Field2D result = DDY(1. / sg, outloc) * DDY(f, outloc) / sg + D2DY2(f, outloc) / g_22; + Field2D result = DDY(1. / sg, outloc, method) * DDY(f, outloc, method) / sg + D2DY2(f, outloc, method) / g_22; return result; } -const Field3D Coordinates::Grad2_par2(const Field3D &f, CELL_LOC outloc) { +const Field3D Coordinates::Grad2_par2(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method) { TRACE("Coordinates::Grad2_par2( Field3D )"); - ASSERT1(location == outloc || outloc == CELL_DEFAULT); + if (outloc == CELL_DEFAULT) { + outloc = f.getLocation(); + } + ASSERT1(location == outloc); Field2D sg(localmesh); Field3D result(localmesh), r2(localmesh); sg = sqrt(g_22); - sg = DDY(1. / sg) / sg; + sg = DDY(1. / sg, outloc, method) / sg; - if (outloc == CELL_DEFAULT) { - outloc = f.getLocation(); - } - if (sg.getLocation() != outloc) { - localmesh->communicate(sg); - sg = interp_to(sg, outloc); - } - - result = ::DDY(f, outloc); + result = ::DDY(f, outloc, method); - r2 = D2DY2(f, outloc) / interp_to(g_22, outloc); + r2 = D2DY2(f, outloc, method) / g_22; result = sg * result + r2; - ASSERT2(((outloc == CELL_DEFAULT) && (result.getLocation() == f.getLocation())) || - (result.getLocation() == outloc)); + ASSERT2(result.getLocation() == outloc); return result; } @@ -785,7 +779,10 @@ const Field2D Coordinates::Delp2(const Field2D &f, CELL_LOC outloc) { const Field3D Coordinates::Delp2(const Field3D &f, CELL_LOC outloc) { TRACE("Coordinates::Delp2( Field3D )"); - ASSERT1(location == outloc || outloc == CELL_DEFAULT); + if (outloc == CELL_DEFAULT) { + outloc = f.getLocation(); + } + ASSERT1(location == outloc); if (localmesh->GlobalNx == 1 && localmesh->GlobalNz == 1) { // copy mesh, location, etc @@ -793,7 +790,6 @@ const Field3D Coordinates::Delp2(const Field3D &f, CELL_LOC outloc) { } ASSERT2(localmesh->xstart > 0); // Need at least one guard cell - if (outloc == CELL_DEFAULT) outloc = f.getLocation(); ASSERT2(f.getLocation() == outloc); Field3D result(localmesh); @@ -855,7 +851,7 @@ const FieldPerp Coordinates::Delp2(const FieldPerp &f, CELL_LOC outloc) { if (outloc == CELL_DEFAULT) outloc = f.getLocation(); - ASSERT1(location == outloc || outloc == CELL_DEFAULT); + ASSERT1(location == outloc); ASSERT2(f.getLocation() == outloc); FieldPerp result(localmesh); diff --git a/src/mesh/data/gridfromfile.cxx b/src/mesh/data/gridfromfile.cxx index 2a2758525e..59fb515271 100644 --- a/src/mesh/data/gridfromfile.cxx +++ b/src/mesh/data/gridfromfile.cxx @@ -407,7 +407,7 @@ bool GridFile::readgrid_3dvar_fft(Mesh *m, const string &name, /// but don't do it yet as we don't assert that m == var.getMesh() /// Expect the assertion to be true, in which case we probably don't /// need to pass m as can just use var.getMesh() - BoutReal zlength = m->coordinates(var.getLocation())->zlength(); + BoutReal zlength = m->getCoordinates(var.getLocation())->zlength(); int zperiod = ROUND(TWOPI / zlength); /// Number of periods in 2pi diff --git a/src/mesh/difops.cxx b/src/mesh/difops.cxx index 58625c77d6..1aaafb7598 100644 --- a/src/mesh/difops.cxx +++ b/src/mesh/difops.cxx @@ -167,7 +167,7 @@ const Field3D Grad_parP(const Field3D &apar, const Field3D &f) { * vparallel times the parallel derivative along unperturbed B-field *******************************************************************************/ -const Field2D Vpar_Grad_par(const Field2D &v, const Field2D &f, const CELL_LOC outloc) { +const Field2D Vpar_Grad_par(const Field2D &v, const Field2D &f, CELL_LOC outloc) { return f.getCoordinates(outloc)->Vpar_Grad_par(v, f, outloc); } @@ -184,7 +184,7 @@ const Field3D Vpar_Grad_par(const Field3D &v, const Field3D &f, DIFF_METHOD meth * parallel divergence operator B \partial_{||} (F/B) *******************************************************************************/ -const Field2D Div_par(const Field2D &f, const CELL_LOC outloc) { +const Field2D Div_par(const Field2D &f, CELL_LOC outloc) { return f.getCoordinates(outloc)->Div_par(f, outloc); } @@ -239,7 +239,25 @@ const Field3D Div_par(const Field3D &f, const Field3D &v) { const Field3D Div_par_flux(const Field3D &v, const Field3D &f, CELL_LOC outloc, DIFF_METHOD method) { Coordinates *metric = f.getCoordinates(outloc); - return metric->Bxy*FDDY(v, f/f.getCoordinates()->Bxy, outloc, method)/sqrt(metric->g_22); + + Field2D Bxy_floc = f.getCoordinates()->Bxy; + + if (!f.hasYupYdown()) { + return metric->Bxy*FDDY(v, f/Bxy_floc, outloc, method)/sqrt(metric->g_22); + } + + // Need to modify yup and ydown fields + Field3D f_B = f / Bxy_floc; + if (&f.yup() == &f) { + // Identity, yup and ydown point to same field + f_B.mergeYupYdown(); + } else { + // Distinct fields + f_B.splitYupYdown(); + 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); } const Field3D Div_par_flux(const Field3D &v, const Field3D &f, DIFF_METHOD method, CELL_LOC outloc) { @@ -342,58 +360,11 @@ const Field3D Vpar_Grad_par_LCtoC(const Field3D &v, const Field3D &f, REGION reg } } } - else if (vUseUpDown) { - // Only v has up/down fields - // f must shift to field aligned coordinates - Field3D f_fa = vMesh->toFieldAligned(f); - - BOUT_OMP(parallel) { - stencil fval, vval; - BOUT_FOR_INNER(i, vMesh->getRegion3D(region_str)) { - fval.mm = f_fa[i.ymm()]; - fval.m = f_fa[i.ym()]; - fval.c = f_fa[i]; - fval.p = f_fa[i.yp()]; - fval.pp = f_fa[i.ypp()]; - - vval.m = v.ydown()[i.ym()]; - vval.c = v[i]; - vval.p = v.yup()[i.yp()]; - - // Left side - result[i] = (vval.c >= 0.0) ? vval.c * fval.m : vval.c * fval.c; - // Right side - result[i] -= (vval.p >= 0.0) ? vval.p * fval.c : vval.p * fval.p; - } - } - } - else if (fUseUpDown) { - // Only f has up/down fields - // v must shift to field aligned coordinates - Field3D v_fa = vMesh->toFieldAligned(v); - - BOUT_OMP(parallel) { - stencil fval, vval; - BOUT_FOR_INNER(i, vMesh->getRegion3D(region_str)) { - fval.m = f.ydown()[i.ym()]; - fval.c = f[i]; - fval.p = f.yup()[i.yp()]; - - vval.mm = v_fa[i.ymm()]; - vval.m = v_fa[i.ym()]; - vval.c = v_fa[i]; - vval.p = v_fa[i.yp()]; - vval.pp = v_fa[i.ypp()]; - - // Left side - result[i] = (vval.c >= 0.0) ? vval.c * fval.m : vval.c * fval.c; - // Right side - result[i] -= (vval.p >= 0.0) ? vval.p * fval.c : vval.p * fval.p; - } - } - } else { // Both must shift to field aligned + // (even if one of v and f has yup/ydown fields, it doesn't make sense to + // multiply them with one in field-aligned and one in non-field-aligned + // coordinates) Field3D v_fa = vMesh->toFieldAligned(v); Field3D f_fa = vMesh->toFieldAligned(f); @@ -413,6 +384,8 @@ const Field3D Vpar_Grad_par_LCtoC(const Field3D &v, const Field3D &f, REGION reg // Right side result[i] -= (vval.p >= 0.0) ? vval.p * fval.c : vval.p * fval.p; } + + result = vMesh->fromFieldAligned(result); } } @@ -534,12 +507,12 @@ const Field3D Div_par_CtoL(const Field3D &var) { * Note: For parallel Laplacian use LaplacePar *******************************************************************************/ -const Field2D Grad2_par2(const Field2D &f, const CELL_LOC outloc) { - return f.getCoordinates(outloc)->Grad2_par2(f, outloc); +const Field2D Grad2_par2(const Field2D &f, CELL_LOC outloc, DIFF_METHOD method) { + return f.getCoordinates(outloc)->Grad2_par2(f, outloc, method); } -const Field3D Grad2_par2(const Field3D &f, const CELL_LOC outloc) { - return f.getCoordinates(outloc)->Grad2_par2(f, outloc); +const Field3D Grad2_par2(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method) { + return f.getCoordinates(outloc)->Grad2_par2(f, outloc, method); } /******************************************************************************* @@ -547,27 +520,27 @@ const Field3D Grad2_par2(const Field3D &f, const CELL_LOC outloc) { * Parallel divergence of diffusive flux, K*Grad_par *******************************************************************************/ -const Field2D Div_par_K_Grad_par(BoutReal kY, const Field2D &f, const CELL_LOC outloc) { +const Field2D Div_par_K_Grad_par(BoutReal kY, const Field2D &f, CELL_LOC outloc) { return kY*Grad2_par2(f, outloc); } -const Field3D Div_par_K_Grad_par(BoutReal kY, const Field3D &f, const CELL_LOC outloc) { +const Field3D Div_par_K_Grad_par(BoutReal kY, const Field3D &f, CELL_LOC outloc) { return kY*Grad2_par2(f, outloc); } -const Field2D Div_par_K_Grad_par(const Field2D &kY, const Field2D &f, const CELL_LOC outloc) { +const Field2D Div_par_K_Grad_par(const Field2D &kY, const Field2D &f, CELL_LOC outloc) { return interp_to(kY, outloc)*Grad2_par2(f, outloc) + Div_par(kY, outloc)*Grad_par(f, outloc); } -const Field3D Div_par_K_Grad_par(const Field2D &kY, const Field3D &f, const CELL_LOC outloc) { +const Field3D Div_par_K_Grad_par(const Field2D &kY, const Field3D &f, CELL_LOC outloc) { return interp_to(kY, outloc)*Grad2_par2(f, outloc) + Div_par(kY, outloc)*Grad_par(f, outloc); } -const Field3D Div_par_K_Grad_par(const Field3D &kY, const Field2D &f, const CELL_LOC outloc) { +const Field3D Div_par_K_Grad_par(const Field3D &kY, const Field2D &f, CELL_LOC outloc) { return interp_to(kY, outloc)*Grad2_par2(f, outloc) + Div_par(kY, outloc)*Grad_par(f, outloc); } -const Field3D Div_par_K_Grad_par(const Field3D &kY, const Field3D &f, const CELL_LOC outloc) { +const Field3D Div_par_K_Grad_par(const Field3D &kY, const Field3D &f, CELL_LOC outloc) { return interp_to(kY, outloc)*Grad2_par2(f, outloc) + Div_par(kY, outloc)*Grad_par(f, outloc); } @@ -576,15 +549,15 @@ const Field3D Div_par_K_Grad_par(const Field3D &kY, const Field3D &f, const CELL * perpendicular Laplacian operator *******************************************************************************/ -const Field2D Delp2(const Field2D &f, const CELL_LOC outloc) { +const Field2D Delp2(const Field2D &f, CELL_LOC outloc) { return f.getCoordinates(outloc)->Delp2(f, outloc); } -const Field3D Delp2(const Field3D &f, BoutReal UNUSED(zsmooth), const CELL_LOC outloc) { +const Field3D Delp2(const Field3D &f, BoutReal UNUSED(zsmooth), CELL_LOC outloc) { return f.getCoordinates(outloc)->Delp2(f, outloc); } -const FieldPerp Delp2(const FieldPerp &f, BoutReal UNUSED(zsmooth), const CELL_LOC outloc) { +const FieldPerp Delp2(const FieldPerp &f, BoutReal UNUSED(zsmooth), CELL_LOC outloc) { return f.getCoordinates(outloc)->Delp2(f, outloc); } @@ -595,11 +568,11 @@ const FieldPerp Delp2(const FieldPerp &f, BoutReal UNUSED(zsmooth), const CELL_L * Laplace_perp = Laplace - Laplace_par *******************************************************************************/ -const Field2D Laplace_perp(const Field2D &f, const CELL_LOC outloc) { +const Field2D Laplace_perp(const Field2D &f, CELL_LOC outloc) { return Laplace(f, outloc) - Laplace_par(f, outloc); } -const Field3D Laplace_perp(const Field3D &f, const CELL_LOC outloc) { +const Field3D Laplace_perp(const Field3D &f, CELL_LOC outloc) { return Laplace(f, outloc) - Laplace_par(f, outloc); } @@ -611,11 +584,11 @@ const Field3D Laplace_perp(const Field3D &f, const CELL_LOC outloc) { * *******************************************************************************/ -const Field2D Laplace_par(const Field2D &f, const CELL_LOC outloc) { +const Field2D Laplace_par(const Field2D &f, CELL_LOC outloc) { return f.getCoordinates(outloc)->Laplace_par(f, outloc); } -const Field3D Laplace_par(const Field3D &f, const CELL_LOC outloc) { +const Field3D Laplace_par(const Field3D &f, CELL_LOC outloc) { return f.getCoordinates(outloc)->Laplace_par(f, outloc); } @@ -624,11 +597,11 @@ const Field3D Laplace_par(const Field3D &f, const CELL_LOC outloc) { * Full Laplacian operator on scalar field *******************************************************************************/ -const Field2D Laplace(const Field2D &f, const CELL_LOC outloc) { +const Field2D Laplace(const Field2D &f, CELL_LOC outloc) { return f.getCoordinates(outloc)->Laplace(f, outloc); } -const Field3D Laplace(const Field3D &f, const CELL_LOC outloc) { +const Field3D Laplace(const Field3D &f, CELL_LOC outloc) { return f.getCoordinates(outloc)->Laplace(f, outloc); } @@ -775,8 +748,7 @@ const Field3D b0xGrad_dot_Grad(const Field3D &phi, const Field3D &A, CELL_LOC ou result.name = "b0xGrad_dot_Grad("+phi.name+","+A.name+")"; #endif - ASSERT2(((outloc == CELL_DEFAULT) && (result.getLocation() == A.getLocation())) || - (result.getLocation() == outloc)); + ASSERT2(result.getLocation() == outloc); return result; } @@ -786,52 +758,26 @@ const Field3D b0xGrad_dot_Grad(const Field3D &phi, const Field3D &A, CELL_LOC ou * Terms of form b0 x Grad(f) dot Grad(g) / B = [f, g] *******************************************************************************/ -/*! - * Calculate location of result - */ -// use anonymous namespace so this function is only available in this file -namespace { - CELL_LOC bracket_location(const CELL_LOC &f_loc, const CELL_LOC &g_loc, const CELL_LOC &outloc, Mesh* localmesh=mesh) { - if(!localmesh->StaggerGrids) - return CELL_CENTRE; - - if(outloc == CELL_DEFAULT){ - // Check that f and g are in the same location - if (f_loc != g_loc){ - throw BoutException("Bracket currently requires both fields to have the same cell location"); - }else { - return f_loc; // Location of result - } - } - - // Check that f, and g are in the same location as the specified output location - if(f_loc != g_loc || f_loc != outloc){ - throw BoutException("Bracket currently requires the location of both fields and the output locaton to be the same"); - } - - return outloc; // Location of result - } -} - const Field2D bracket(const Field2D &f, const Field2D &g, BRACKET_METHOD method, CELL_LOC outloc, Solver *UNUSED(solver)) { TRACE("bracket(Field2D, Field2D)"); ASSERT1(f.getMesh() == g.getMesh()); + if (outloc == CELL_DEFAULT) { + outloc = g.getLocation(); + } + ASSERT1(f.getLocation() == g.getLocation() && outloc == f.getLocation()) Field2D result(f.getMesh()); - // Sort out cell locations - CELL_LOC result_loc = bracket_location(f.getLocation(), g.getLocation(), outloc, f.getMesh()); - if( (method == BRACKET_SIMPLE) || (method == BRACKET_ARAKAWA)) { // Use a subset of terms for comparison to BOUT-06 result = 0.0; + result.setLocation(outloc); }else { // Use full expression with all terms - result = b0xGrad_dot_Grad(f, g) / f.getCoordinates(result_loc)->Bxy; + result = b0xGrad_dot_Grad(f, g, outloc) / f.getCoordinates(outloc)->Bxy; } - result.setLocation(result_loc); return result; } @@ -840,14 +786,16 @@ const Field3D bracket(const Field3D &f, const Field2D &g, BRACKET_METHOD method, TRACE("bracket(Field3D, Field2D)"); ASSERT1(f.getMesh() == g.getMesh()); + if (outloc == CELL_DEFAULT) { + outloc = g.getLocation(); + } + ASSERT1(f.getLocation() == g.getLocation() && outloc == f.getLocation()) Mesh *mesh = f.getMesh(); Field3D result(mesh); - CELL_LOC result_loc = bracket_location(f.getLocation(), g.getLocation(), outloc, f.getMesh()); - - Coordinates *metric = f.getCoordinates(result_loc); + Coordinates *metric = f.getCoordinates(outloc); switch(method) { case BRACKET_CTU: { @@ -858,6 +806,7 @@ const Field3D bracket(const Field3D &f, const Field2D &g, BRACKET_METHOD method, throw BoutException("CTU method requires access to the solver"); result.allocate(); + result.setLocation(outloc); int ncz = mesh->LocalNz; for(int x=mesh->xstart;x<=mesh->xend;x++) @@ -895,6 +844,7 @@ const Field3D bracket(const Field3D &f, const Field2D &g, BRACKET_METHOD method, // Arakawa scheme for perpendicular flow. Here as a test result.allocate(); + result.setLocation(outloc); const BoutReal fac = 1.0 / (12 * metric->dz); const int ncz = mesh->LocalNz; @@ -965,6 +915,7 @@ const Field3D bracket(const Field3D &f, const Field2D &g, BRACKET_METHOD method, } case BRACKET_ARAKAWA_OLD: { result.allocate(); + result.setLocation(outloc); const int ncz = mesh->LocalNz; const BoutReal partialFactor = 1.0/(12 * metric->dz); BOUT_OMP(parallel for) @@ -1004,15 +955,14 @@ const Field3D bracket(const Field3D &f, const Field2D &g, BRACKET_METHOD method, } case BRACKET_SIMPLE: { // Use a subset of terms for comparison to BOUT-06 - result = VDDX(DDZ(f), g); + result = VDDX(DDZ(f, outloc), g, outloc); break; } default: { // Use full expression with all terms - result = b0xGrad_dot_Grad(f, g) / metric->Bxy; + result = b0xGrad_dot_Grad(f, g, outloc) / metric->Bxy; } } - result.setLocation(result_loc); return result; } @@ -1021,13 +971,15 @@ const Field3D bracket(const Field2D &f, const Field3D &g, BRACKET_METHOD method, TRACE("bracket(Field2D, Field3D)"); ASSERT1(f.getMesh() == g.getMesh()); + if (outloc == CELL_DEFAULT) { + outloc = g.getLocation(); + } + ASSERT1(f.getLocation() == g.getLocation() && outloc == f.getLocation()) Mesh *mesh = f.getMesh(); Field3D result(mesh); - CELL_LOC result_loc = bracket_location(f.getLocation(), g.getLocation(), outloc, f.getMesh()); - switch(method) { case BRACKET_CTU: throw BoutException("Bracket method CTU is not yet implemented for [2d,3d] fields."); @@ -1038,16 +990,15 @@ const Field3D bracket(const Field2D &f, const Field3D &g, BRACKET_METHOD method, break; case BRACKET_SIMPLE: { // Use a subset of terms for comparison to BOUT-06 - result = VDDZ(-DDX(f), g); + result = VDDZ(-DDX(f, outloc), g, outloc); break; } default: { // Use full expression with all terms - Coordinates *metric = f.getCoordinates(result_loc); - result = b0xGrad_dot_Grad(f, g) / metric->Bxy; + Coordinates *metric = f.getCoordinates(outloc); + result = b0xGrad_dot_Grad(f, g, outloc) / metric->Bxy; } } - result.setLocation(result_loc) ; return result; } @@ -1057,18 +1008,20 @@ const Field3D bracket(const Field3D &f, const Field3D &g, BRACKET_METHOD method, TRACE("Field3D, Field3D"); ASSERT1(f.getMesh() == g.getMesh()); + if (outloc == CELL_DEFAULT) { + outloc = g.getLocation(); + } + ASSERT1(f.getLocation() == g.getLocation() && outloc == f.getLocation()) Mesh *mesh = f.getMesh(); Field3D result(mesh); - CELL_LOC result_loc = bracket_location(f.getLocation(), g.getLocation(), outloc, f.getMesh()); - - Coordinates *metric = f.getCoordinates(result_loc); + Coordinates *metric = f.getCoordinates(outloc); if (mesh->GlobalNx == 1 || mesh->GlobalNz == 1) { result=0; - result.setLocation(result_loc); + result.setLocation(outloc); return result; } @@ -1084,6 +1037,7 @@ const Field3D bracket(const Field3D &f, const Field3D &g, BRACKET_METHOD method, BoutReal dt = solver->getCurrentTimestep(); result.allocate(); + result.setLocation(outloc); FieldPerp vx(mesh), vz(mesh); vx.allocate(); @@ -1174,6 +1128,7 @@ const Field3D bracket(const Field3D &f, const Field3D &g, BRACKET_METHOD method, // Arakawa scheme for perpendicular flow result.allocate(); + result.setLocation(outloc); const int ncz = mesh->LocalNz; const BoutReal partialFactor = 1.0/(12 * metric->dz); @@ -1267,6 +1222,7 @@ const Field3D bracket(const Field3D &f, const Field3D &g, BRACKET_METHOD method, // Arakawa scheme for perpendicular flow result.allocate(); + result.setLocation(outloc); const int ncz = mesh->LocalNz; const BoutReal partialFactor = 1.0 / (12 * metric->dz); @@ -1316,16 +1272,14 @@ const Field3D bracket(const Field3D &f, const Field3D &g, BRACKET_METHOD method, } case BRACKET_SIMPLE: { // Use a subset of terms for comparison to BOUT-06 - result = VDDX(DDZ(f), g) + VDDZ(-DDX(f), g); + result = VDDX(DDZ(f, outloc), g, outloc) + VDDZ(-DDX(f, outloc), g, outloc); break; } default: { // Use full expression with all terms - result = b0xGrad_dot_Grad(f, g) / metric->Bxy; + result = b0xGrad_dot_Grad(f, g, outloc) / metric->Bxy; } } - result.setLocation(result_loc) ; - return result; } diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index 1ebbed117d..e4f3c487a0 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -2553,5 +2553,5 @@ void BoutMesh::outputVars(Datafile &file) { file.add(jyseps2_1, "jyseps2_1", false); file.add(jyseps2_2, "jyseps2_2", false); - coordinates()->outputVars(file); + getCoordinates()->outputVars(file); } diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index d872b70ab4..f684cce292 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -662,6 +662,7 @@ const Field2D Mesh::applyXdiff(const Field2D &var, Mesh::deriv_func func, Field2D result(this); result.allocate(); // Make sure data allocated + result.setLocation(outloc); if (this->StaggerGrids && (outloc != inloc)) { // Staggered differencing @@ -752,8 +753,6 @@ const Field2D Mesh::applyXdiff(const Field2D &var, Mesh::deriv_func func, } } - result.setLocation(outloc); - #if CHECK > 0 // Mark boundaries as invalid result.bndry_xin = result.bndry_xout = result.bndry_yup = result.bndry_ydown = false; @@ -787,6 +786,7 @@ const Field3D Mesh::applyXdiff(const Field3D &var, Mesh::deriv_func func, Field3D result(this); result.allocate(); // Make sure data allocated + result.setLocation(outloc); if (this->StaggerGrids && (outloc != inloc)) { // Staggered differencing @@ -877,8 +877,6 @@ const Field3D Mesh::applyXdiff(const Field3D &var, Mesh::deriv_func func, } } - result.setLocation(outloc); - #if CHECK > 0 // Mark boundaries as invalid result.bndry_xin = result.bndry_xout = result.bndry_yup = result.bndry_ydown = false; @@ -912,6 +910,7 @@ const Field2D Mesh::applyYdiff(const Field2D &var, Mesh::deriv_func func, CELL_L Field2D result(this); result.allocate(); // Make sure data allocated + result.setLocation(outloc); if (this->ystart > 1) { // More than one guard cell, so set pp and mm values @@ -943,8 +942,6 @@ const Field2D Mesh::applyYdiff(const Field2D &var, Mesh::deriv_func func, CELL_L } } - result.setLocation(outloc); - #if CHECK > 0 // Mark boundaries as invalid result.bndry_yup = result.bndry_ydown = false; @@ -977,6 +974,7 @@ const Field3D Mesh::applyYdiff(const Field3D &var, Mesh::deriv_func func, CELL_L Field3D result(this); result.allocate(); // Make sure data allocated + result.setLocation(outloc); if (var.hasYupYdown() && ((&var.yup() != &var) || (&var.ydown() != &var))) { // Field "var" has distinct yup and ydown fields which @@ -1122,8 +1120,6 @@ const Field3D Mesh::applyYdiff(const Field3D &var, Mesh::deriv_func func, CELL_L result = this->fromFieldAligned(result); } - result.setLocation(outloc); - #if CHECK > 0 // Mark boundaries as invalid result.bndry_xin = result.bndry_xout = result.bndry_yup = result.bndry_ydown = false; @@ -1156,6 +1152,7 @@ const Field3D Mesh::applyZdiff(const Field3D &var, Mesh::deriv_func func, CELL_L Field3D result(this); result.allocate(); // Make sure data allocated + result.setLocation(outloc); // Check that the input variable has data ASSERT1(var.isAllocated()); @@ -1174,8 +1171,6 @@ const Field3D Mesh::applyZdiff(const Field3D &var, Mesh::deriv_func func, CELL_L } } - result.setLocation(outloc); - return result; } @@ -1197,8 +1192,6 @@ const Field3D Mesh::indexDDX(const Field3D &f, CELL_LOC outloc, DIFF_METHOD meth ASSERT1(outloc == inloc || (outloc == CELL_CENTRE && inloc == CELL_XLOW) || (outloc == CELL_XLOW && inloc == CELL_CENTRE)); - Field3D result(this); - if (this->StaggerGrids && (outloc != inloc)) { // Shifting in X. Centre -> Xlow, or Xlow -> Centre @@ -1213,9 +1206,7 @@ const Field3D Mesh::indexDDX(const Field3D &f, CELL_LOC outloc, DIFF_METHOD meth throw BoutException("Cannot use FFT for X derivatives"); } - result = applyXdiff(f, func, outloc, region); - - return result; + return applyXdiff(f, func, outloc, region); } const Field2D Mesh::indexDDX(const Field2D &f, CELL_LOC outloc, @@ -1239,8 +1230,6 @@ const Field3D Mesh::indexDDY(const Field3D &f, CELL_LOC outloc, DIFF_METHOD meth ASSERT1(outloc == inloc || (outloc == CELL_CENTRE && inloc == CELL_YLOW) || (outloc == CELL_YLOW && inloc == CELL_CENTRE)); - Field3D result(this); - if (this->StaggerGrids && (outloc != inloc)) { // Shifting in Y. Centre -> Ylow, or Ylow -> Centre func = sfDDY; // Set default @@ -1254,9 +1243,7 @@ const Field3D Mesh::indexDDY(const Field3D &f, CELL_LOC outloc, DIFF_METHOD meth throw BoutException("Cannot use FFT for Y derivatives"); } - result = applyYdiff(f, func, outloc, region); - - return result; + return applyYdiff(f, func, outloc, region); } const Field2D Mesh::indexDDY(const Field2D &f, CELL_LOC outloc, @@ -1420,8 +1407,6 @@ const Field3D Mesh::indexD2DX2(const Field3D &f, CELL_LOC outloc, ASSERT1(this == f.getMesh()); - Field3D result(this); - if (StaggerGrids && (outloc != inloc)) { // Shifting in X. Centre -> Xlow, or Xlow -> Centre func = sfD2DX2; // Set default @@ -1435,9 +1420,7 @@ const Field3D Mesh::indexD2DX2(const Field3D &f, CELL_LOC outloc, throw BoutException("Cannot use FFT for X derivatives"); } - result = applyXdiff(f, func, outloc, region); - - return result; + return applyXdiff(f, func, outloc, region); } /*! @@ -1483,8 +1466,6 @@ const Field3D Mesh::indexD2DY2(const Field3D &f, CELL_LOC outloc, ASSERT1(outloc == inloc || (outloc == CELL_CENTRE && inloc == CELL_YLOW) || (outloc == CELL_YLOW && inloc == CELL_CENTRE)); - Field3D result(this); - if (StaggerGrids && (outloc != inloc)) { // Shifting in Y. Centre -> Ylow, or Ylow -> Centre func = sfD2DY2; // Set default @@ -1498,9 +1479,7 @@ const Field3D Mesh::indexD2DY2(const Field3D &f, CELL_LOC outloc, throw BoutException("Cannot use FFT for Y derivatives"); } - result = applyYdiff(f, func, outloc, region); - - return result; + return applyYdiff(f, func, outloc, region); } /*! @@ -1726,6 +1705,7 @@ const Field2D Mesh::indexVDDX(const Field2D &v, const Field2D &f, CELL_LOC outlo Field2D result(this); result.allocate(); // Make sure data allocated + result.setLocation(outloc); if (this->xstart > 1) { // Two or more guard cells @@ -1761,8 +1741,6 @@ const Field2D Mesh::indexVDDX(const Field2D &v, const Field2D &f, CELL_LOC outlo result.bndry_xin = result.bndry_xout = false; #endif - result.setLocation(outloc); - return result; } @@ -1776,6 +1754,7 @@ const Field3D Mesh::indexVDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo ASSERT1(this == v.getMesh()); ASSERT1(this == f.getMesh()); + CELL_LOC vloc = v.getLocation(); CELL_LOC inloc = f.getLocation(); // Input location if (outloc == CELL_DEFAULT) @@ -1787,6 +1766,7 @@ const Field3D Mesh::indexVDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo Field3D result(this); result.allocate(); // Make sure data allocated + result.setLocation(outloc); /// Convert REGION enum to a Region string identifier const auto region_str = REGION_STRING(region); @@ -1926,8 +1906,6 @@ const Field3D Mesh::indexVDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo } } - result.setLocation(outloc); - #if CHECK > 0 // Mark boundaries as invalid result.bndry_xin = result.bndry_xout = result.bndry_yup = result.bndry_ydown = false; @@ -1957,10 +1935,10 @@ const Field2D Mesh::indexVDDY(const Field2D &v, const Field2D &f, CELL_LOC outlo Field2D result(this); result.allocate(); // Make sure data allocated + result.setLocation(outloc); if (this->LocalNy == 1){ result=0; - result.setLocation(outloc); return result; } @@ -2102,8 +2080,6 @@ const Field2D Mesh::indexVDDY(const Field2D &v, const Field2D &f, CELL_LOC outlo } } - result.setLocation(outloc); - #if CHECK > 0 // Mark boundaries as invalid result.bndry_xin = result.bndry_xout = result.bndry_yup = result.bndry_ydown = false; @@ -2131,10 +2107,10 @@ const Field3D Mesh::indexVDDY(const Field3D &v, const Field3D &f, CELL_LOC outlo Field3D result(this); result.allocate(); // Make sure data allocated + result.setLocation(outloc); if (this->LocalNy == 1){ result=0; - result.setLocation(outloc); return result; } @@ -2158,12 +2134,8 @@ const Field3D Mesh::indexVDDY(const Field3D &v, const Field3D &f, CELL_LOC outlo func = lookupFunc(table, method); } - // There are four cases, corresponding to whether or not f and v - // have yup, ydown fields. - - // If vUseUpDown is true, field "v" has distinct yup and ydown fields which - // will be used to calculate a derivative along - // the magnetic field + // If *UseUpDown is true, field "*" has distinct yup and ydown fields which + // will be used to calculate a derivative along the magnetic field bool vUseUpDown = (v.hasYupYdown() && ((&v.yup() != &v) || (&v.ydown() != &v))); bool fUseUpDown = (f.hasYupYdown() && ((&f.yup() != &f) || (&f.ydown() != &f))); @@ -2195,6 +2167,9 @@ const Field3D Mesh::indexVDDY(const Field3D &v, const Field3D &f, CELL_LOC outlo } } else { // Both must shift to field aligned + // (even if one of v and f has yup/ydown fields, it doesn't make sense to + // multiply them with one in field-aligned and one in non-field-aligned + // coordinates) Field3D v_fa = this->toFieldAligned(v); Field3D f_fa = this->toFieldAligned(f); BOUT_OMP(parallel) { @@ -2208,7 +2183,7 @@ const Field3D Mesh::indexVDDY(const Field3D &v, const Field3D &f, CELL_LOC outlo fval.mm = f_fa[i.ymm()]; fval.m = f_fa[i.ym()]; - fval.c = f[i]; + fval.c = f_fa[i]; fval.p = f_fa[i.yp()]; fval.pp = f_fa[i.ypp()]; @@ -2225,6 +2200,8 @@ const Field3D Mesh::indexVDDY(const Field3D &v, const Field3D &f, CELL_LOC outlo result[i] = func(vval, fval); } } + + result = this->fromFieldAligned(result); } } else { // Non-staggered case @@ -2286,8 +2263,6 @@ const Field3D Mesh::indexVDDY(const Field3D &v, const Field3D &f, CELL_LOC outlo } } - result.setLocation(outloc); - #if CHECK > 0 // Mark boundaries as invalid result.bndry_xin = result.bndry_xout = result.bndry_yup = result.bndry_ydown = false; @@ -2317,6 +2292,7 @@ const Field3D Mesh::indexVDDZ(const Field3D &v, const Field3D &f, CELL_LOC outlo Field3D result(this); result.allocate(); // Make sure data allocated + result.setLocation(outloc); /// Convert REGION enum to a Region string identifier const auto region_str = REGION_STRING(region); @@ -2387,8 +2363,6 @@ const Field3D Mesh::indexVDDZ(const Field3D &v, const Field3D &f, CELL_LOC outlo } } - result.setLocation(outloc); - #if CHECK > 0 // Mark boundaries as invalid result.bndry_xin = result.bndry_xout = result.bndry_yup = result.bndry_ydown = false; @@ -2426,6 +2400,7 @@ const Field2D Mesh::indexFDDX(const Field2D &v, const Field2D &f, CELL_LOC outlo Field2D result(this); result.allocate(); // Make sure data allocated + result.setLocation(outloc); ASSERT1(this == v.getMesh()); ASSERT1(this == f.getMesh()); @@ -2520,6 +2495,7 @@ const Field3D Mesh::indexFDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo Field3D result(this); result.allocate(); // Make sure data allocated + result.setLocation(outloc); /// Convert REGION enum to a Region string identifier const auto region_str = REGION_STRING(region); @@ -2651,8 +2627,6 @@ const Field3D Mesh::indexFDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo } } - result.setLocation(outloc); - #if CHECK > 0 // Mark boundaries as invalid result.bndry_xin = result.bndry_xout = result.bndry_yup = result.bndry_ydown = false; @@ -2690,7 +2664,7 @@ const Field2D Mesh::indexFDDY(const Field2D &v, const Field2D &f, CELL_LOC outlo Field2D result(this); result.allocate(); // Make sure data allocated - result.setLocation(f.getLocation()); + result.setLocation(outloc); /// Convert REGION enum to a Region string identifier const auto region_str = REGION_STRING(region); @@ -2734,8 +2708,6 @@ const Field2D Mesh::indexFDDY(const Field2D &v, const Field2D &f, CELL_LOC outlo } } - result.setLocation(outloc); - #if CHECK > 0 // Mark boundaries as invalid result.bndry_xin = result.bndry_xout = false; @@ -2787,13 +2759,10 @@ const Field3D Mesh::indexFDDY(const Field3D &v, const Field3D &f, CELL_LOC outlo Field3D result(this); result.allocate(); // Make sure data allocated + result.setLocation(outloc); - // There are four cases, corresponding to whether or not f and v - // have yup, ydown fields. - - // If vUseUpDown is true, field "v" has distinct yup and ydown fields which - // will be used to calculate a derivative along - // the magnetic field + // If *UseUpDown is true, field "*" has distinct yup and ydown fields which + // will be used to calculate a derivative along the magnetic field bool vUseUpDown = (v.hasYupYdown() && ((&v.yup() != &v) || (&v.ydown() != &v))); bool fUseUpDown = (f.hasYupYdown() && ((&f.yup() != &f) || (&f.ydown() != &f))); @@ -2830,6 +2799,9 @@ const Field3D Mesh::indexFDDY(const Field3D &v, const Field3D &f, CELL_LOC outlo } } else { // Both must shift to field aligned + // (even if one of v and f has yup/ydown fields, it doesn't make sense to + // multiply them with one in field-aligned and one in non-field-aligned + // coordinates) Field3D v_fa = this->toFieldAligned(v); Field3D f_fa = this->toFieldAligned(f); BOUT_OMP(parallel) { @@ -2862,9 +2834,9 @@ const Field3D Mesh::indexFDDY(const Field3D &v, const Field3D &f, CELL_LOC outlo result[i] = func(vval, fval); } } - } - result.setLocation(outloc); + result = this->fromFieldAligned(result); + } #if CHECK > 0 // Mark boundaries as invalid @@ -2916,6 +2888,7 @@ const Field3D Mesh::indexFDDZ(const Field3D &v, const Field3D &f, CELL_LOC outlo Field3D result(this); result.allocate(); // Make sure data allocated + result.setLocation(outloc); /// Convert REGION enum to a Region string identifier const auto region_str = REGION_STRING(region); @@ -2951,7 +2924,6 @@ const Field3D Mesh::indexFDDZ(const Field3D &v, const Field3D &f, CELL_LOC outlo result[i] = func(vval, fval); } } - result.setLocation(outloc); #if CHECK > 0 // Mark boundaries as invalid diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 34b1c7709f..6a857f57a7 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -331,28 +331,28 @@ std::shared_ptr Mesh::createDefaultCoordinates(const CELL_LOC locat return std::make_shared(this); else // Interpolate coordinates from CELL_CENTRE version - return std::make_shared(this, location, coordinates(CELL_CENTRE)); + return std::make_shared(this, location, getCoordinates(CELL_CENTRE)); } -Region<> & Mesh::getRegion3D(const std::string ®ion_name){ - auto found = regionMap3D.find(region_name); - if (found == end(regionMap3D)) { - throw BoutException("Couldn't find region %s in regionMap3D", region_name.c_str()); - } - return found->second; +const Region<> & Mesh::getRegion3D(const std::string ®ion_name) const { + const auto found = regionMap3D.find(region_name); + if (found == end(regionMap3D)) { + throw BoutException("Couldn't find region %s in regionMap3D", region_name.c_str()); + } + return found->second; } -Region & Mesh::getRegion2D(const std::string ®ion_name){ - auto found = regionMap2D.find(region_name); - if (found == end(regionMap2D)) { - throw BoutException("Couldn't find region %s in regionMap2D", region_name.c_str()); - } - return found->second; +const Region & Mesh::getRegion2D(const std::string ®ion_name) const { + const auto found = regionMap2D.find(region_name); + if (found == end(regionMap2D)) { + throw BoutException("Couldn't find region %s in regionMap2D", region_name.c_str()); + } + return found->second; } -Region &Mesh::getRegionPerp(const std::string ®ion_name) { - auto found = regionMapPerp.find(region_name); +const Region &Mesh::getRegionPerp(const std::string ®ion_name) const { + const auto found = regionMapPerp.find(region_name); if (found == end(regionMapPerp)) { throw BoutException("Couldn't find region %s in regionMapPerp", region_name.c_str()); } diff --git a/src/mesh/parallel/fci.cxx b/src/mesh/parallel/fci.cxx index 63f53856a7..25002ffed3 100644 --- a/src/mesh/parallel/fci.cxx +++ b/src/mesh/parallel/fci.cxx @@ -137,7 +137,7 @@ FCIMap::FCIMap(Mesh &mesh, int dir, bool zperiodic) int ncz = mesh.LocalNz; BoutReal t_x, t_z; - Coordinates &coord = *(mesh.coordinates()); + Coordinates &coord = *(mesh.getCoordinates()); for (int x = mesh.xstart; x <= mesh.xend; x++) { for (int y = mesh.ystart; y <= mesh.yend; y++) { diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 13067fe07c..80fdc37274 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -23,6 +23,15 @@ ShiftedMetric::ShiftedMetric(Mesh &m) : mesh(m), zShift(&m) { mesh.get(zShift, "qinty"); } + // TwistShift needs to be set for derivatives to be correct at the jump where + // poloidal angle theta goes 2pi->0 + bool twistshift = Options::root()["TwistShift"].withDefault(false); + bool shift_without_twist = Options::root()["ShiftWithoutTwist"].withDefault(false); + if (!twistshift and !shift_without_twist) { + throw BoutException("ShiftedMetric usually requires the option TwistShift=true\n" + " Set ShiftWithoutTwist=true to use ShiftedMetric without TwistShift"); + } + //If we wanted to be efficient we could move the following cached phase setup //into the relevant shifting routines (with static bool first protection) //so that we only calculate the phase if we actually call a relevant shift @@ -33,7 +42,7 @@ ShiftedMetric::ShiftedMetric(Mesh &m) : mesh(m), zShift(&m) { //not change once we've been created so precalculate the complex //phases used in transformations int nmodes = mesh.LocalNz/2 + 1; - BoutReal zlength = mesh.coordinates()->zlength(); + BoutReal zlength = mesh.getCoordinates()->zlength(); //Allocate storage for complex intermediate cmplx.resize(nmodes); @@ -195,7 +204,7 @@ void ShiftedMetric::shiftZ(const BoutReal *in, int len, BoutReal zangle, BoutRe rfft(in, len, &cmplxLoc[0]); // Apply phase shift - BoutReal zlength = mesh.coordinates()->zlength(); + BoutReal zlength = mesh.getCoordinates()->zlength(); for(int jz=1;jzcoordinates(); + coords = mesh->getCoordinates(); // Switches in model section Options *optgbs = opt->getSection("GBS"); diff --git a/tests/MMS/advection/advection.cxx b/tests/MMS/advection/advection.cxx index 178bd94961..ee6d93ff34 100644 --- a/tests/MMS/advection/advection.cxx +++ b/tests/MMS/advection/advection.cxx @@ -18,7 +18,7 @@ class AdvectMMS : public PhysicsModel { } int rhs(BoutReal time) { mesh->communicate(f); - Coordinates *coords = mesh->coordinates(); + Coordinates *coords = mesh->getCoordinates(); g = FieldFactory::get()->create3D("g:solution", Options::getRoot(), mesh, CELL_CENTRE, time); diff --git a/tests/MMS/diffusion/diffusion.cxx b/tests/MMS/diffusion/diffusion.cxx index dba3b21515..b89a0b0e6a 100644 --- a/tests/MMS/diffusion/diffusion.cxx +++ b/tests/MMS/diffusion/diffusion.cxx @@ -28,7 +28,7 @@ int physics_init(bool restarting) { // Get the options Options *meshoptions = Options::getRoot()->getSection("mesh"); - coord = mesh->coordinates(); + coord = mesh->getCoordinates(); meshoptions->get("Lx",Lx,1.0); meshoptions->get("Ly",Ly,1.0); diff --git a/tests/MMS/diffusion2/diffusion.cxx b/tests/MMS/diffusion2/diffusion.cxx index 1071ab5f85..4a0fffbd45 100644 --- a/tests/MMS/diffusion2/diffusion.cxx +++ b/tests/MMS/diffusion2/diffusion.cxx @@ -13,7 +13,7 @@ BoutReal Lx, Ly, Lz; int physics_init(bool restarting) { // Get the options Options *meshoptions = Options::getRoot()->getSection("mesh"); - Coordinates *coords = mesh->coordinates(); + Coordinates *coords = mesh->getCoordinates(); meshoptions->get("Lx",Lx,1.0); meshoptions->get("Ly",Ly,1.0); diff --git a/tests/MMS/elm-pb/elm_pb.cxx b/tests/MMS/elm-pb/elm_pb.cxx index c0750e018d..3ae0e27594 100644 --- a/tests/MMS/elm-pb/elm_pb.cxx +++ b/tests/MMS/elm-pb/elm_pb.cxx @@ -153,7 +153,7 @@ int physics_init(bool restarting) { mesh->get(hthe, "hthe"); // m mesh->get(I, "sinty");// m^-2 T^-1 - Coordinates *coords = mesh->coordinates(); + Coordinates *coords = mesh->getCoordinates(); ////////////////////////////////////////////////////////////// // Read parameters from the options file @@ -505,7 +505,7 @@ int physics_run(BoutReal t) { // Perform communications mesh->communicate(comms); - Coordinates *coords = mesh->coordinates(); + Coordinates *coords = mesh->getCoordinates(); //////////////////////////////////////////// // Transitions from 0 in core to 1 in vacuum diff --git a/tests/MMS/fieldalign/fieldalign.cxx b/tests/MMS/fieldalign/fieldalign.cxx index 48f84b3857..ccd20ca7fa 100644 --- a/tests/MMS/fieldalign/fieldalign.cxx +++ b/tests/MMS/fieldalign/fieldalign.cxx @@ -13,7 +13,7 @@ class FieldAlign : public PhysicsModel { } int rhs(BoutReal t) { - Coordinates *metric = mesh->coordinates(); + Coordinates *metric = mesh->getCoordinates(); mesh->communicate(f); f.applyBoundary(t); diff --git a/tests/MMS/hw/hw.cxx b/tests/MMS/hw/hw.cxx index 5e79e7ea7f..20ca7d6c8c 100644 --- a/tests/MMS/hw/hw.cxx +++ b/tests/MMS/hw/hw.cxx @@ -36,8 +36,8 @@ int physics_init(bool restart) { /*this assumes equidistant grid*/ int nguard = mesh->xstart; - mesh->coordinates()->dx = Lx/(mesh->GlobalNx - 2*nguard); - mesh->coordinates()->dz = TWOPI*Lx/(mesh->LocalNz); + mesh->getCoordinates()->dx = Lx/(mesh->GlobalNx - 2*nguard); + mesh->getCoordinates()->dz = TWOPI*Lx/(mesh->LocalNz); ///// SOLVE_FOR2(n, vort); diff --git a/tests/MMS/laplace/laplace.cxx b/tests/MMS/laplace/laplace.cxx index 49a2d57bf5..e762637af1 100644 --- a/tests/MMS/laplace/laplace.cxx +++ b/tests/MMS/laplace/laplace.cxx @@ -20,8 +20,8 @@ int main(int argc, char **argv) { /*this assumes equidistant grid*/ int nguard = mesh->xstart; - mesh->coordinates()->dx = Lx/(mesh->GlobalNx - 2*nguard); - mesh->coordinates()->dz = TWOPI*Lx/(mesh->LocalNz); + mesh->getCoordinates()->dx = Lx/(mesh->GlobalNx - 2*nguard); + mesh->getCoordinates()->dz = TWOPI*Lx/(mesh->LocalNz); ///// // Create a Laplacian inversion solver diff --git a/tests/MMS/spatial/advection/advection.cxx b/tests/MMS/spatial/advection/advection.cxx index 178bd94961..ee6d93ff34 100644 --- a/tests/MMS/spatial/advection/advection.cxx +++ b/tests/MMS/spatial/advection/advection.cxx @@ -18,7 +18,7 @@ class AdvectMMS : public PhysicsModel { } int rhs(BoutReal time) { mesh->communicate(f); - Coordinates *coords = mesh->coordinates(); + Coordinates *coords = mesh->getCoordinates(); g = FieldFactory::get()->create3D("g:solution", Options::getRoot(), mesh, CELL_CENTRE, time); diff --git a/tests/MMS/spatial/diffusion/diffusion.cxx b/tests/MMS/spatial/diffusion/diffusion.cxx index 13aa3089f9..ca673fa8c5 100644 --- a/tests/MMS/spatial/diffusion/diffusion.cxx +++ b/tests/MMS/spatial/diffusion/diffusion.cxx @@ -14,7 +14,7 @@ int physics_init(bool restarting) { // Get the options Options *meshoptions = Options::getRoot()->getSection("mesh"); - Coordinates *coords = mesh->coordinates(); + Coordinates *coords = mesh->getCoordinates(); meshoptions->get("Lx",Lx,1.0); meshoptions->get("Ly",Ly,1.0); diff --git a/tests/MMS/tokamak/tokamak.cxx b/tests/MMS/tokamak/tokamak.cxx index 6e5dbb5386..a917afe960 100644 --- a/tests/MMS/tokamak/tokamak.cxx +++ b/tests/MMS/tokamak/tokamak.cxx @@ -29,7 +29,7 @@ class TokamakMMS : public PhysicsModel { // Test bracket advection operator ddt(advect) = -1e-3*bracket(drive, advect, BRACKET_ARAKAWA) - - 10.*(SQ(SQ(mesh->coordinates()->dx))*D4DX4(advect) + SQ(SQ(mesh->coordinates()->dz))*D4DZ4(advect)); + - 10.*(SQ(SQ(mesh->getCoordinates()->dx))*D4DX4(advect) + SQ(SQ(mesh->getCoordinates()->dz))*D4DZ4(advect)); // Test perpendicular diffusion operator ddt(delp2) = 1e-5*Delp2(delp2); @@ -44,7 +44,7 @@ class TokamakMMS : public PhysicsModel { Field2D Rxy, Bpxy, Btxy, hthe, sinty; GRID_LOAD5(Rxy, Bpxy, Btxy, hthe, sinty); // Load metrics - Coordinates *coords = mesh->coordinates(); + Coordinates *coords = mesh->getCoordinates(); // Checking for dpsi used in BOUT grids Field2D dx; diff --git a/tests/MMS/wave-1d/wave.cxx b/tests/MMS/wave-1d/wave.cxx index 188f1bebdd..d2543a98b1 100644 --- a/tests/MMS/wave-1d/wave.cxx +++ b/tests/MMS/wave-1d/wave.cxx @@ -23,7 +23,7 @@ const Field3D HLL(const Field3D &f, const Field3D &u, BoutReal SL, BoutReal SR) Field3D result; result.allocate(); - Coordinates *coord = mesh->coordinates(); + Coordinates *coord = mesh->getCoordinates(); for(int i=mesh->xstart;i<=mesh->xend;i++) for(int j=mesh->ystart; j<=mesh->yend; j++) @@ -52,7 +52,7 @@ class Wave1D : public PhysicsModel { protected: int init(bool restarting) { // Coordinate system - coord = mesh->coordinates(); + coord = mesh->getCoordinates(); // Get the options Options *meshoptions = Options::getRoot()->getSection("mesh"); diff --git a/tests/integrated/test-drift-instability/2fluid.cxx b/tests/integrated/test-drift-instability/2fluid.cxx index ee0e1faa84..3e55a2c6fb 100644 --- a/tests/integrated/test-drift-instability/2fluid.cxx +++ b/tests/integrated/test-drift-instability/2fluid.cxx @@ -86,7 +86,7 @@ int physics_init(bool restarting) { mesh->get(b0xcv, "bxcv"); // b0xkappa terms // Coordinate system - coord = mesh->coordinates(); + coord = mesh->getCoordinates(); // Load metrics GRID_LOAD(Rxy); diff --git a/tests/integrated/test-fci-slab/fci_slab.cxx b/tests/integrated/test-fci-slab/fci_slab.cxx index d5841a89e4..84ba090355 100644 --- a/tests/integrated/test-fci-slab/fci_slab.cxx +++ b/tests/integrated/test-fci-slab/fci_slab.cxx @@ -12,7 +12,7 @@ class FCISlab : public PhysicsModel { D = 10; - Coordinates *coord = mesh->coordinates(); + Coordinates *coord = mesh->getCoordinates(); mesh->get(coord->g_22, "g_22"); @@ -40,7 +40,7 @@ BOUTMAIN(FCISlab); int FCISlab::rhs(BoutReal time) { mesh->communicate(f,g); - Coordinates *coord = mesh->coordinates(); + Coordinates *coord = mesh->getCoordinates(); f.applyParallelBoundary(time); g.applyParallelBoundary(time); diff --git a/tests/integrated/test-interchange-instability/2fluid.cxx b/tests/integrated/test-interchange-instability/2fluid.cxx index 1376bf1e38..ff1fd8524b 100644 --- a/tests/integrated/test-interchange-instability/2fluid.cxx +++ b/tests/integrated/test-interchange-instability/2fluid.cxx @@ -54,7 +54,7 @@ class Interchange : public PhysicsModel { b0xcv *= -1.0; // NOTE: THIS IS FOR 'OLD' GRID FILES ONLY // Coordinate system - coord = mesh->coordinates(); + coord = mesh->getCoordinates(); // Load metrics GRID_LOAD(Rxy); diff --git a/tests/integrated/test-multigrid_laplace/test_multigrid_laplace.cxx b/tests/integrated/test-multigrid_laplace/test_multigrid_laplace.cxx index e538d6e5e5..0f5f107c5c 100644 --- a/tests/integrated/test-multigrid_laplace/test_multigrid_laplace.cxx +++ b/tests/integrated/test-multigrid_laplace/test_multigrid_laplace.cxx @@ -52,8 +52,8 @@ int main(int argc, char** argv) { BoutReal nx = mesh->GlobalNx-2*mesh->xstart; BoutReal nz = mesh->GlobalNz; - dump.add(mesh->coordinates()->G1,"G1"); - dump.add(mesh->coordinates()->G3,"G3"); + dump.add(mesh->getCoordinates()->G1,"G1"); + dump.add(mesh->getCoordinates()->G3,"G3"); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Test 1: zero-value Dirichlet boundaries @@ -231,13 +231,13 @@ int main(int argc, char** argv) { if (mesh->firstX()) for (int k=0;kLocalNz;k++) x0(mesh->xstart-1,mesh->ystart,k) = (f4(mesh->xstart,mesh->ystart,k)-f4(mesh->xstart-1,mesh->ystart,k)) - /mesh->coordinates()->dx(mesh->xstart,mesh->ystart) - /sqrt(mesh->coordinates()->g_11(mesh->xstart,mesh->ystart)); + /mesh->getCoordinates()->dx(mesh->xstart,mesh->ystart) + /sqrt(mesh->getCoordinates()->g_11(mesh->xstart,mesh->ystart)); if (mesh->lastX()) for (int k=0;kLocalNz;k++) x0(mesh->xend+1,mesh->ystart,k) = (f4(mesh->xend+1,mesh->ystart,k)-f4(mesh->xend,mesh->ystart,k)) - /mesh->coordinates()->dx(mesh->xend,mesh->ystart) - /sqrt(mesh->coordinates()->g_11(mesh->xend,mesh->ystart)); + /mesh->getCoordinates()->dx(mesh->xend,mesh->ystart) + /sqrt(mesh->getCoordinates()->g_11(mesh->xend,mesh->ystart)); try { sol4 = invert->solve(sliceXZ(b4, mesh->ystart), sliceXZ(x0, mesh->ystart)); @@ -283,16 +283,16 @@ int main(int argc, char** argv) { // Delp2 uses FFT z-derivatives and Laplace includes y-derivatives, so can't use those // The function is a copy of Laplace() with the y-derivatives deleted Field3D this_Grad_perp2(const Field3D &f) { - Field3D result = mesh->coordinates()->G1 * ::DDX(f) + mesh->coordinates()->G3 * ::DDZ(f) + - mesh->coordinates()->g11 * ::D2DX2(f) + mesh->coordinates()->g33 * ::D2DZ2(f) + - 2.0 * mesh->coordinates()->g13 * ::D2DXDZ(f); + Field3D result = mesh->getCoordinates()->G1 * ::DDX(f) + mesh->getCoordinates()->G3 * ::DDZ(f) + + mesh->getCoordinates()->g11 * ::D2DX2(f) + mesh->getCoordinates()->g33 * ::D2DZ2(f) + + 2.0 * mesh->getCoordinates()->g13 * ::D2DXDZ(f); return result; } Field3D this_Grad_perp_dot_Grad_perp(const Field3D &f, const Field3D &g) { - Field3D result = mesh->coordinates()->g11 * ::DDX(f) * ::DDX(g) + mesh->coordinates()->g33 * ::DDZ(f) * ::DDZ(g) - + mesh->coordinates()->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 3dde5d5d12..8a5f1f8103 100644 --- a/tests/integrated/test-naulin-laplace/test_naulin_laplace.cxx +++ b/tests/integrated/test-naulin-laplace/test_naulin_laplace.cxx @@ -54,8 +54,8 @@ int main(int argc, char** argv) { BoutReal nx = mesh->GlobalNx-2*mesh->xstart; BoutReal nz = mesh->GlobalNz; - dump.add(mesh->coordinates()->G1,"G1"); - dump.add(mesh->coordinates()->G3,"G3"); + dump.add(mesh->getCoordinates()->G1,"G1"); + dump.add(mesh->getCoordinates()->G3,"G3"); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Test 1: zero-value Dirichlet boundaries @@ -238,13 +238,13 @@ int main(int argc, char** argv) { if (mesh->firstX()) for (int k=0;kLocalNz;k++) x0(mesh->xstart-1,mesh->ystart,k) = (f4(mesh->xstart,mesh->ystart,k)-f4(mesh->xstart-1,mesh->ystart,k)) - /mesh->coordinates()->dx(mesh->xstart,mesh->ystart) - /sqrt(mesh->coordinates()->g_11(mesh->xstart,mesh->ystart)); + /mesh->getCoordinates()->dx(mesh->xstart,mesh->ystart) + /sqrt(mesh->getCoordinates()->g_11(mesh->xstart,mesh->ystart)); if (mesh->lastX()) for (int k=0;kLocalNz;k++) x0(mesh->xend+1,mesh->ystart,k) = (f4(mesh->xend+1,mesh->ystart,k)-f4(mesh->xend,mesh->ystart,k)) - /mesh->coordinates()->dx(mesh->xend,mesh->ystart) - /sqrt(mesh->coordinates()->g_11(mesh->xend,mesh->ystart)); + /mesh->getCoordinates()->dx(mesh->xend,mesh->ystart) + /sqrt(mesh->getCoordinates()->g_11(mesh->xend,mesh->ystart)); try { sol4 = invert->solve(b4, x0); @@ -289,8 +289,8 @@ int main(int argc, char** argv) { } Field3D this_Grad_perp_dot_Grad_perp(const Field3D &f, const Field3D &g) { - Field3D result = mesh->coordinates()->g11 * ::DDX(f) * ::DDX(g) + mesh->coordinates()->g33 * ::DDZ(f) * ::DDZ(g) - + mesh->coordinates()->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-squash/.gitignore b/tests/integrated/test-squash/.gitignore new file mode 100644 index 0000000000..a12058acc2 --- /dev/null +++ b/tests/integrated/test-squash/.gitignore @@ -0,0 +1,2 @@ +*.nc +squash \ No newline at end of file diff --git a/tests/integrated/test-squash/data/BOUT.inp b/tests/integrated/test-squash/data/BOUT.inp new file mode 100644 index 0000000000..3253314f8d --- /dev/null +++ b/tests/integrated/test-squash/data/BOUT.inp @@ -0,0 +1,22 @@ +timestep = 1. +nout = 1 + +MZ = 1 + +[mesh] +MXG=1 +MYG=1 +nx = 4 +ny = 2 + +dx = 1. +dy = 1. + +[solver] + +[f2] +scale = 1. +function = 0. + +[f3] +function = 0. diff --git a/tests/integrated/test-squash/makefile b/tests/integrated/test-squash/makefile new file mode 100644 index 0000000000..cecff798ec --- /dev/null +++ b/tests/integrated/test-squash/makefile @@ -0,0 +1,6 @@ + +BOUT_TOP = ../../.. + +SOURCEC = squash.cxx + +include $(BOUT_TOP)/make.config diff --git a/tests/integrated/test-squash/runtest b/tests/integrated/test-squash/runtest new file mode 100755 index 0000000000..cc440597bf --- /dev/null +++ b/tests/integrated/test-squash/runtest @@ -0,0 +1,101 @@ +#!/usr/bin/env python3 + +from boututils.datafile import DataFile +import itertools +import time +import numpy as np +from boututils.run_wrapper import launch_safe, shell_safe + +#requires: all_tests +#requires: netcdf + + +class timer(object): + """Context manager for printing how long a command took + + """ + def __init__(self, msg): + self.msg = msg + + def __enter__(self): + self.start = time.time() + + def __exit__(self, exc_type, exc_value, traceback): + end = time.time() + print("{:12.8f}s {}".format(end - self.start, self.msg)) + + +def timed_shell_safe(cmd, *args, **kwargs): + """Wraps shell_safe in a timer + + """ + with timer(cmd): + shell_safe(cmd, *args, **kwargs) + + +def timed_launch_safe(cmd, *args, **kwargs): + """Wraps launch_safe in a timer + + """ + with timer(cmd): + launch_safe(cmd, *args, **kwargs) + + +def verify(f1, f2): + """Verifies that two BOUT++ files are identical + + """ + with timer("verify %s %s" % (f1, f2)): + d1 = DataFile(f1) + d2 = DataFile(f2) + for v in d1.keys(): + if d1[v].shape != d2[v].shape: + raise RuntimeError("shape mismatch in ", v, d1[v], d2[v]) + if v in ["MXSUB", "MYSUB", "NXPE", "NYPE", "iteration"]: + continue + if not np.allclose(d1[v], d2[v]): + err = "" + dimensions = [range(x) for x in d1[v].shape] + for i in itertools.product(*dimensions): + if d1[v][i] != d2[v][i]: + err += "{}: {} != {}\n".format(i, d1[v][i], d2[v][i]) + raise RuntimeError("data mismatch in ", v, err, d1[v], d2[v]) + + +timed_shell_safe("make") + +# Run once to get normal data +timed_shell_safe("./squash -q -q -q nout=2") +timed_shell_safe("mv data/BOUT.dmp.0.nc f1.nc") + +# Parallel test +timed_shell_safe("rm -f f2.nc") +timed_launch_safe("./squash -q -q -q nout=2", nproc=4, mthread=1) +timed_shell_safe("../../../bin/bout-squashoutput -qdcl 9 data --outputname ../f2.nc") + +verify("f1.nc", "f2.nc") + +# Parallel and in two pieces +timed_shell_safe("rm -f f2.nc") +timed_launch_safe("./squash -q -q -q", nproc=4, mthread=1) +timed_shell_safe("../../../bin/bout-squashoutput -qdcl 9 data --outputname ../f2.nc") +timed_launch_safe("./squash -q -q -q restart", nproc=4, mthread=1) +timed_shell_safe("../../../bin/bout-squashoutput -qdcal 9 data --outputname ../f2.nc") + +verify("f1.nc", "f2.nc") + +# Parallel and in two pieces without dump_on_restart +timed_shell_safe("rm -f f2.nc") +timed_launch_safe("./squash -q -q -q", nproc=4, mthread=1) +timed_shell_safe("../../../bin/bout-squashoutput -qdcl 9 data --outputname ../f2.nc") +timed_launch_safe("./squash -q -q -q restart dump_on_restart=false", nproc=4, mthread=1) +timed_shell_safe("../../../bin/bout-squashoutput -qdcal 9 data --outputname ../f2.nc") + +verify("f1.nc", "f2.nc") + +# Sequential test +timed_shell_safe("rm -f f2.nc") +timed_shell_safe("./squash -q -q -q nout=2") +timed_shell_safe("../../../bin/bout-squashoutput -qdcl 9 data --outputname ../f2.nc") + +verify("f1.nc", "f2.nc") diff --git a/tests/integrated/test-squash/squash.cxx b/tests/integrated/test-squash/squash.cxx new file mode 100644 index 0000000000..98528ba860 --- /dev/null +++ b/tests/integrated/test-squash/squash.cxx @@ -0,0 +1,30 @@ +/* + */ + +#include + +class SquashRun : public PhysicsModel { +protected: + // Initialisation + int init(bool restarting) { + solver->add(f2, "f2"); + solver->add(f3, "f3"); + return 0; + } + + // Calculate time-derivatives + int rhs(BoutReal t) { + ddt(f2) = 1; + ddt(f3) = -1; + f2.applyBoundary(); + f3.applyBoundary(); + return 0; + } + +private: + Field2D f2; + Field3D f3; +}; + +// Create a default main() +BOUTMAIN(SquashRun); diff --git a/tests/integrated/test-yupdown/data/BOUT.inp b/tests/integrated/test-yupdown/data/BOUT.inp index f905f9c36c..46604e38e7 100644 --- a/tests/integrated/test-yupdown/data/BOUT.inp +++ b/tests/integrated/test-yupdown/data/BOUT.inp @@ -1,3 +1,4 @@ +ShiftWithoutTwist = true [mesh] nx = 12 diff --git a/tests/unit/field/test_vector2d.cxx b/tests/unit/field/test_vector2d.cxx index ffeda89eaf..7824f2b2cf 100644 --- a/tests/unit/field/test_vector2d.cxx +++ b/tests/unit/field/test_vector2d.cxx @@ -111,6 +111,75 @@ TEST_F(Vector2DTest, TimeDeriv) { EXPECT_EQ(&(ddt(vector)), deriv); } +TEST_F(Vector2DTest, SetLocationNonStaggered) { + Vector2D vector; + EXPECT_EQ(vector.getLocation(), CELL_CENTRE); + EXPECT_NO_THROW(vector.setLocation(CELL_CENTRE)); + EXPECT_EQ(vector.getLocation(), CELL_CENTRE); +#if CHECK > 0 + EXPECT_THROW(vector.setLocation(CELL_XLOW), BoutException); +#endif +} + +TEST_F(Vector2DTest, SetLocationXLOW) { + Vector2D vector; + CELL_LOC targetLoc = CELL_XLOW; + vector.x.getMesh()->StaggerGrids = true; + EXPECT_EQ(vector.getLocation(), CELL_CENTRE); + EXPECT_NO_THROW(vector.setLocation(targetLoc)); + EXPECT_EQ(vector.getLocation(), targetLoc); + EXPECT_EQ(vector.x.getLocation(), targetLoc); + EXPECT_EQ(vector.y.getLocation(), targetLoc); + EXPECT_EQ(vector.z.getLocation(), targetLoc); +} + +TEST_F(Vector2DTest, SetLocationYLOW) { + Vector2D vector; + CELL_LOC targetLoc = CELL_YLOW; + vector.x.getMesh()->StaggerGrids = true; + EXPECT_EQ(vector.getLocation(), CELL_CENTRE); + EXPECT_NO_THROW(vector.setLocation(targetLoc)); + EXPECT_EQ(vector.getLocation(), targetLoc); + EXPECT_EQ(vector.x.getLocation(), targetLoc); + EXPECT_EQ(vector.y.getLocation(), targetLoc); + EXPECT_EQ(vector.z.getLocation(), targetLoc); +} + +TEST_F(Vector2DTest, SetLocationZLOW) { + Vector2D vector; + CELL_LOC targetLoc = CELL_ZLOW; + vector.x.getMesh()->StaggerGrids = true; + EXPECT_EQ(vector.getLocation(), CELL_CENTRE); + EXPECT_NO_THROW(vector.setLocation(targetLoc)); + EXPECT_EQ(vector.getLocation(), targetLoc); + EXPECT_EQ(vector.x.getLocation(), targetLoc); + EXPECT_EQ(vector.y.getLocation(), targetLoc); + EXPECT_EQ(vector.z.getLocation(), targetLoc); +} + +TEST_F(Vector2DTest, SetLocationVSHIFT) { + Vector2D vector; + vector.x.getMesh()->StaggerGrids = true; + EXPECT_EQ(vector.getLocation(), CELL_CENTRE); + EXPECT_NO_THROW(vector.setLocation(CELL_VSHIFT)); + EXPECT_EQ(vector.getLocation(), CELL_VSHIFT); + EXPECT_EQ(vector.x.getLocation(), CELL_XLOW); + EXPECT_EQ(vector.y.getLocation(), CELL_YLOW); + EXPECT_EQ(vector.z.getLocation(), CELL_ZLOW); +} + +TEST_F(Vector2DTest, SetLocationDEFAULT) { + Vector2D vector; + CELL_LOC targetLoc = CELL_CENTRE; + vector.x.getMesh()->StaggerGrids = true; + EXPECT_EQ(vector.getLocation(), CELL_CENTRE); + EXPECT_NO_THROW(vector.setLocation(CELL_DEFAULT)); + EXPECT_EQ(vector.getLocation(), targetLoc); + EXPECT_EQ(vector.x.getLocation(), targetLoc); + EXPECT_EQ(vector.y.getLocation(), targetLoc); + EXPECT_EQ(vector.z.getLocation(), targetLoc); +} + TEST_F(Vector2DTest, AssignFromBoutReal) { Vector2D vector; @@ -123,28 +192,38 @@ TEST_F(Vector2DTest, AssignFromBoutReal) { TEST_F(Vector2DTest, AssignFromVector2D) { Vector2D vector1, vector2; + + vector1.x.getMesh()->StaggerGrids = true; + vector1.x = 1.0; vector1.y = 2.0; vector1.z = 3.0; + vector1.setLocation(CELL_XLOW); vector2 = vector1; EXPECT_TRUE(IsField2DEqualBoutReal(vector2.x, 1.0)); EXPECT_TRUE(IsField2DEqualBoutReal(vector2.y, 2.0)); EXPECT_TRUE(IsField2DEqualBoutReal(vector2.z, 3.0)); + EXPECT_EQ(vector1.getLocation(), vector2.getLocation()); } TEST_F(Vector2DTest, CreateFromVector2D) { Vector2D vector1; + + vector1.x.getMesh()->StaggerGrids = true; + vector1.x = 4.0; vector1.y = 5.0; vector1.z = 6.0; + vector1.setLocation(CELL_YLOW); Vector2D vector2{vector1}; EXPECT_TRUE(IsField2DEqualBoutReal(vector2.x, 4.0)); EXPECT_TRUE(IsField2DEqualBoutReal(vector2.y, 5.0)); EXPECT_TRUE(IsField2DEqualBoutReal(vector2.z, 6.0)); + EXPECT_EQ(vector1.getLocation(), vector2.getLocation()); } TEST_F(Vector2DTest, UnaryMinus) { diff --git a/tests/unit/field/test_vector3d.cxx b/tests/unit/field/test_vector3d.cxx index a60157bd9d..fb77078781 100644 --- a/tests/unit/field/test_vector3d.cxx +++ b/tests/unit/field/test_vector3d.cxx @@ -110,6 +110,75 @@ TEST_F(Vector3DTest, TimeDeriv) { EXPECT_EQ(&(ddt(vector)), deriv); } +TEST_F(Vector3DTest, SetLocationNonStaggered) { + Vector3D vector; + EXPECT_EQ(vector.getLocation(), CELL_CENTRE); + EXPECT_NO_THROW(vector.setLocation(CELL_CENTRE)); + EXPECT_EQ(vector.getLocation(), CELL_CENTRE); +#if CHECK > 0 + EXPECT_THROW(vector.setLocation(CELL_XLOW), BoutException); +#endif +} + +TEST_F(Vector3DTest, SetLocationXLOW) { + Vector3D vector; + CELL_LOC targetLoc = CELL_XLOW; + vector.x.getMesh()->StaggerGrids = true; + EXPECT_EQ(vector.getLocation(), CELL_CENTRE); + EXPECT_NO_THROW(vector.setLocation(targetLoc)); + EXPECT_EQ(vector.getLocation(), targetLoc); + EXPECT_EQ(vector.x.getLocation(), targetLoc); + EXPECT_EQ(vector.y.getLocation(), targetLoc); + EXPECT_EQ(vector.z.getLocation(), targetLoc); +} + +TEST_F(Vector3DTest, SetLocationYLOW) { + Vector3D vector; + CELL_LOC targetLoc = CELL_YLOW; + vector.x.getMesh()->StaggerGrids = true; + EXPECT_EQ(vector.getLocation(), CELL_CENTRE); + EXPECT_NO_THROW(vector.setLocation(targetLoc)); + EXPECT_EQ(vector.getLocation(), targetLoc); + EXPECT_EQ(vector.x.getLocation(), targetLoc); + EXPECT_EQ(vector.y.getLocation(), targetLoc); + EXPECT_EQ(vector.z.getLocation(), targetLoc); +} + +TEST_F(Vector3DTest, SetLocationZLOW) { + Vector3D vector; + CELL_LOC targetLoc = CELL_ZLOW; + vector.x.getMesh()->StaggerGrids = true; + EXPECT_EQ(vector.getLocation(), CELL_CENTRE); + EXPECT_NO_THROW(vector.setLocation(targetLoc)); + EXPECT_EQ(vector.getLocation(), targetLoc); + EXPECT_EQ(vector.x.getLocation(), targetLoc); + EXPECT_EQ(vector.y.getLocation(), targetLoc); + EXPECT_EQ(vector.z.getLocation(), targetLoc); +} + +TEST_F(Vector3DTest, SetLocationVSHIFT) { + Vector3D vector; + vector.x.getMesh()->StaggerGrids = true; + EXPECT_EQ(vector.getLocation(), CELL_CENTRE); + EXPECT_NO_THROW(vector.setLocation(CELL_VSHIFT)); + EXPECT_EQ(vector.getLocation(), CELL_VSHIFT); + EXPECT_EQ(vector.x.getLocation(), CELL_XLOW); + EXPECT_EQ(vector.y.getLocation(), CELL_YLOW); + EXPECT_EQ(vector.z.getLocation(), CELL_ZLOW); +} + +TEST_F(Vector3DTest, SetLocationDEFAULT) { + Vector3D vector; + CELL_LOC targetLoc = CELL_CENTRE; + vector.x.getMesh()->StaggerGrids = true; + EXPECT_EQ(vector.getLocation(), CELL_CENTRE); + EXPECT_NO_THROW(vector.setLocation(CELL_DEFAULT)); + EXPECT_EQ(vector.getLocation(), targetLoc); + EXPECT_EQ(vector.x.getLocation(), targetLoc); + EXPECT_EQ(vector.y.getLocation(), targetLoc); + EXPECT_EQ(vector.z.getLocation(), targetLoc); +} + TEST_F(Vector3DTest, AssignFromBoutReal) { Vector3D vector; @@ -120,30 +189,59 @@ TEST_F(Vector3DTest, AssignFromBoutReal) { EXPECT_TRUE(IsField3DEqualBoutReal(vector.z, 0.0)); } +TEST_F(Vector3DTest, AssignFromVector2D) { + Vector2D vector1; + Vector3D vector2; + + vector1.x.getMesh()->StaggerGrids = true; + + vector1.x = 1.0; + vector1.y = 2.0; + vector1.z = 3.0; + vector1.setLocation(CELL_XLOW); + + vector2 = vector1; + + EXPECT_TRUE(IsField3DEqualBoutReal(vector2.x, 1.0)); + EXPECT_TRUE(IsField3DEqualBoutReal(vector2.y, 2.0)); + EXPECT_TRUE(IsField3DEqualBoutReal(vector2.z, 3.0)); + EXPECT_EQ(vector1.getLocation(), vector2.getLocation()); +} + TEST_F(Vector3DTest, AssignFromVector3D) { Vector3D vector1, vector2; + + vector1.x.getMesh()->StaggerGrids = true; + vector1.x = 1.0; vector1.y = 2.0; vector1.z = 3.0; + vector1.setLocation(CELL_XLOW); vector2 = vector1; EXPECT_TRUE(IsField3DEqualBoutReal(vector2.x, 1.0)); EXPECT_TRUE(IsField3DEqualBoutReal(vector2.y, 2.0)); EXPECT_TRUE(IsField3DEqualBoutReal(vector2.z, 3.0)); + EXPECT_EQ(vector1.getLocation(), vector2.getLocation()); } TEST_F(Vector3DTest, CreateFromVector3D) { Vector3D vector1; + + vector1.x.getMesh()->StaggerGrids = true; + vector1.x = 4.0; vector1.y = 5.0; vector1.z = 6.0; + vector1.setLocation(CELL_YLOW); Vector3D vector2{vector1}; EXPECT_TRUE(IsField3DEqualBoutReal(vector2.x, 4.0)); EXPECT_TRUE(IsField3DEqualBoutReal(vector2.y, 5.0)); EXPECT_TRUE(IsField3DEqualBoutReal(vector2.z, 6.0)); + EXPECT_EQ(vector1.getLocation(), vector2.getLocation()); } TEST_F(Vector3DTest, UnaryMinus) { diff --git a/tools/idllib/collect.pro b/tools/idllib/collect.pro index 6fcc78fb90..7c30b22bb5 100644 --- a/tools/idllib/collect.pro +++ b/tools/idllib/collect.pro @@ -20,6 +20,8 @@ FUNCTION collect, arg, xind=xind, yind=yind, zind=zind, tind=tind, $ path=path, var=var, t_array=t_array, use=use, old=old, $ quiet=quiet, debug=debug, prefix=prefix + MESSAGE, "This is currently broken for BOUT++ > v4.0.0. See issue #394" + IF NOT KEYWORD_SET(prefix) THEN prefix="BOUT.dmp" IF NOT KEYWORD_SET(debug) THEN BEGIN diff --git a/tools/mathematicalib/BoutCollect.m b/tools/mathematicalib/BoutCollect.m index b664812092..ae92fde2ed 100644 --- a/tools/mathematicalib/BoutCollect.m +++ b/tools/mathematicalib/BoutCollect.m @@ -7,6 +7,8 @@ {Xind,Yind,Zind,Tind,Path,Yguards,Info,Prefix, varnameissymbol,vars,position,dimensions,nxpe,nype,mxsub,mysub,mxg,myg,mz,tarray,files,nfiles,data,tempdata,ts,te,xs,xe,ys,ye,zs,ze,localx,localy,import,lxs,lxe,lys,lye}, + Throw["This is currently broken for BOUT++ > v4.0.0. See issue #394"] + Xind=OptionValue[xind]; Yind=OptionValue[yind]; Zind=OptionValue[zind]; diff --git a/tools/matlablib/import_data_netcdf.m b/tools/matlablib/import_data_netcdf.m index 31795f0d19..c3c3772840 100644 --- a/tools/matlablib/import_data_netcdf.m +++ b/tools/matlablib/import_data_netcdf.m @@ -21,6 +21,8 @@ % Last two variables important only for [X,Y,Z,T] format and any number % will be ok if we wish to plot [X,Y,Z] and [X,Y] type data. +error("This is currently broken for BOUT++ > v4.0.0. See issue #394") + % Check input arguments if ( nargin < 4 ) fprintf('\tBoth dump file path and variable name are requisite input arguments.\n'); diff --git a/tools/matlablib/import_dmp.m b/tools/matlablib/import_dmp.m index adadd93e8b..e5baa7f416 100644 --- a/tools/matlablib/import_dmp.m +++ b/tools/matlablib/import_dmp.m @@ -9,6 +9,8 @@ % % Coded by Minwoo Kim(Mar. 2012) +error("This is currently broken for BOUT++ > v4.0.0. See issue #394") + % Check input arguments if ( nargin < 2 ) fprintf('\tBoth dump file path and variable name are requisite input arguments.\n'); diff --git a/tools/octave/bcollect.m b/tools/octave/bcollect.m index 0005f4c726..d1128daf19 100644 --- a/tools/octave/bcollect.m +++ b/tools/octave/bcollect.m @@ -17,6 +17,7 @@ # Collect metadata from collection of data files function desc = bcollect(path) + error("This is currently broken for BOUT++ > v4.0.0. See issue #394") narg = nargin(); if (narg < 1) # No path specified, so use current directory diff --git a/tools/pylib/boutdata/squashoutput.py b/tools/pylib/boutdata/squashoutput.py index 0c8ac48029..52bcaa40d1 100644 --- a/tools/pylib/boutdata/squashoutput.py +++ b/tools/pylib/boutdata/squashoutput.py @@ -20,6 +20,11 @@ from boututils.boutarray import BoutArray import numpy import os +import gc +import tempfile +import shutil +import glob + def squashoutput(datadir=".", outputname="BOUT.dmp.nc", format="NETCDF4", tind=None, xind=None, yind=None, zind=None, singleprecision=False, compress=False, @@ -72,59 +77,68 @@ def squashoutput(datadir=".", outputname="BOUT.dmp.nc", format="NETCDF4", tind=N Delete the original files after squashing. """ - import gc - - fullpath = os.path.join(datadir,outputname) + fullpath = os.path.join(datadir, outputname) if append: - import tempfile - import shutil - import glob datadirnew = tempfile.mkdtemp(dir=datadir) - for f in glob.glob(datadir+"/BOUT.dmp.*.??"): + for f in glob.glob(datadir + "/BOUT.dmp.*.??"): if not quiet: - print("moving",f) - shutil.move(f,datadirnew) - oldfile=datadirnew+"/"+outputname - datadir=datadirnew + print("moving", f) + shutil.move(f, datadirnew) + oldfile = datadirnew + "/" + outputname + datadir = datadirnew if os.path.isfile(fullpath) and not append: - raise ValueError(fullpath+" already exists. Collect may try to read from this file, which is presumably not desired behaviour.") + raise ValueError( + fullpath + " already exists. Collect may try to read from this file, which is presumably not desired behaviour.") # useful object from BOUT pylib to access output data - outputs = BoutOutputs(datadir, info=False, xguards=True, yguards=True, tind=tind, xind=xind, yind=yind, zind=zind) + outputs = BoutOutputs(datadir, info=False, xguards=True, + yguards=True, tind=tind, xind=xind, yind=yind, zind=zind) outputvars = outputs.keys() # Read a value to cache the files outputs[outputvars[0]] if append: # move only after the file list is cached - shutil.move(fullpath,oldfile) + shutil.move(fullpath, oldfile) t_array_index = outputvars.index("t_array") outputvars.append(outputvars.pop(t_array_index)) - kwargs={} + kwargs = {} if compress: - kwargs['zlib']=True + kwargs['zlib'] = True if least_significant_digit is not None: - kwargs['least_significant_digit']=least_significant_digit + kwargs['least_significant_digit'] = least_significant_digit if complevel is not None: - kwargs['complevel']=complevel + kwargs['complevel'] = complevel if append: - old=DataFile(oldfile) + old = DataFile(oldfile) + # Check if dump on restart was enabled + # If so, we want to drop the duplicated entry + cropnew = 0 + if old['t_array'][-1] == outputs['t_array'][0]: + cropnew = 1 + # Make sure we don't end up with duplicated data: + for ot in old['t_array']: + if ot in outputs['t_array'][cropnew:]: + raise RuntimeError( + "For some reason t_array has some duplicated entries in the new and old file.") # Create single file for output and write data - with DataFile(fullpath,create=True,write=True,format=format, **kwargs) as f: + with DataFile(fullpath, create=True, write=True, format=format, **kwargs) as f: for varname in outputvars: if not quiet: print(varname) var = outputs[varname] if append: - dims=old.dimensions(varname) + dims = outputs.dimensions[varname] if 't' in dims: - varold=old[varname] - var=BoutArray(numpy.append(varold,var,axis=0),var.attributes) + var = var[cropnew:, ...] + varold = old[varname] + var = BoutArray(numpy.append( + varold, var, axis=0), var.attributes) if singleprecision: if not isinstance(var, int): @@ -133,15 +147,15 @@ def squashoutput(datadir=".", outputname="BOUT.dmp.nc", format="NETCDF4", tind=N f.write(varname, var) # Write changes, free memory f.sync() - var=None + var = None gc.collect() if delete: if append: os.remove(oldfile) - for f in glob.glob(datadir+"/BOUT.dmp.*.??"): + for f in glob.glob(datadir + "/BOUT.dmp.*.??"): if not quiet: - print("Deleting",f) + print("Deleting", f) os.remove(f) if append: os.rmdir(datadir)