From 912436896a4a2537b9579ee16ee5f773e9935afa Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 16 Oct 2018 16:59:45 +0100 Subject: [PATCH 01/45] Add Mesh::GlobalZ methods for consistency with GlobalX, GlobalY Also add override keywords for GlobalX, GlobalY and GlobalZ in BoutMesh declaration. --- include/bout/mesh.hxx | 2 ++ src/mesh/impls/bout/boutmesh.cxx | 8 ++++++++ src/mesh/impls/bout/boutmesh.hxx | 10 ++++++---- tests/unit/test_extras.hxx | 2 ++ 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 056294bbe0..080159e349 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -403,8 +403,10 @@ class Mesh { virtual BoutReal GlobalX(int jx) const = 0; ///< Continuous X index between 0 and 1 virtual BoutReal GlobalY(int jy) const = 0; ///< Continuous Y index (0 -> 1) + virtual BoutReal GlobalZ(int jz) const = 0; ///< Continuous Z index (0 -> 1) virtual BoutReal GlobalX(BoutReal jx) const = 0; ///< Continuous X index between 0 and 1 virtual BoutReal GlobalY(BoutReal jy) const = 0; ///< Continuous Y index (0 -> 1) + virtual BoutReal GlobalZ(BoutReal jz) const = 0; ///< Continuous Z index (0 -> 1) ////////////////////////////////////////////////////////// diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index e4f3c487a0..85f2233f80 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -2533,6 +2533,14 @@ BoutReal BoutMesh::GlobalY(BoutReal jy) const { return yglo / static_cast(nycore); } +BoutReal BoutMesh::GlobalZ(int jz) const { + return static_cast(jz) / static_cast(GlobalNz); +} + +BoutReal BoutMesh::GlobalZ(BoutReal jz) const { + return jz / static_cast(GlobalNz); +} + void BoutMesh::outputVars(Datafile &file) { file.add(zperiod, "zperiod", false); file.add(MXSUB, "MXSUB", false); diff --git a/src/mesh/impls/bout/boutmesh.hxx b/src/mesh/impls/bout/boutmesh.hxx index 8b8fb97ee1..91d6c25036 100644 --- a/src/mesh/impls/bout/boutmesh.hxx +++ b/src/mesh/impls/bout/boutmesh.hxx @@ -147,10 +147,12 @@ class BoutMesh : public Mesh { int getNx() const {return nx;} int getNy() const {return ny;} - BoutReal GlobalX(int jx) const; - BoutReal GlobalY(int jy) const; - BoutReal GlobalX(BoutReal jx) const; - BoutReal GlobalY(BoutReal jy) const; + BoutReal GlobalX(int jx) const override; + BoutReal GlobalY(int jy) const override; + BoutReal GlobalZ(int jz) const override; + BoutReal GlobalX(BoutReal jx) const override; + BoutReal GlobalY(BoutReal jy) const override; + BoutReal GlobalZ(BoutReal jz) const override; BoutReal getIxseps1() const {return ixseps1;} BoutReal getIxseps2() const {return ixseps2;} diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index 6e6c9dc2ad..becb73bcfd 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -149,8 +149,10 @@ public: vector getBoundariesPar() { return vector(); } BoutReal GlobalX(int UNUSED(jx)) const { return 0; } BoutReal GlobalY(int UNUSED(jy)) const { return 0; } + BoutReal GlobalZ(int UNUSED(jz)) const { return 0; } BoutReal GlobalX(BoutReal UNUSED(jx)) const { return 0; } BoutReal GlobalY(BoutReal UNUSED(jy)) const { return 0; } + BoutReal GlobalZ(BoutReal UNUSED(jz)) const { return 0; } int XGLOBAL(int UNUSED(xloc)) const { return 0; } int YGLOBAL(int UNUSED(yloc)) const { return 0; } From ff40d3323c82acbbfbd6d9e6927c4d3489b31150 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 17 Oct 2018 19:06:16 +0100 Subject: [PATCH 02/45] Add Mesh* pointer to FieldData Add a Mesh* pointer and getDataMesh() method to FieldData, so that FieldData::setBoundary() can use the local mesh. getDataMesh() method is needed in case the FieldData is constructed before the global mesh is created (i.e. when Field3D, etc. are declared in global scope). It must not be called getMesh() because that would clash with the method of Field. --- include/field_data.hxx | 11 ++++++++++- src/field/field2d.cxx | 8 ++++++-- src/field/field3d.cxx | 13 +++++++------ src/field/field_data.cxx | 17 ++++++++++------- src/field/vector2d.cxx | 9 ++++++--- src/field/vector3d.cxx | 11 ++++++++--- 6 files changed, 47 insertions(+), 22 deletions(-) diff --git a/include/field_data.hxx b/include/field_data.hxx index c4fadd4e95..d75e89c2ca 100644 --- a/include/field_data.hxx +++ b/include/field_data.hxx @@ -62,12 +62,20 @@ class FieldVisitor; */ class FieldData { public: - FieldData(); + FieldData(Mesh* m); virtual ~FieldData(); // Visitor pattern support virtual void accept(FieldVisitor &v) = 0; + virtual Mesh * getDataMesh() const{ + if (fielddatamesh){ + 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 +100,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/src/field/field2d.cxx b/src/field/field2d.cxx index a675039078..0346179738 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,6 +67,7 @@ Field2D::Field2D(Mesh *localmesh) : Field(localmesh), deriv(nullptr) { } Field2D::Field2D(const Field2D& f) : Field(f.fieldmesh), // The mesh containing array sizes + FieldData(f.fieldmesh), data(f.data), // This handles references to the data array deriv(nullptr) { TRACE("Field2D(Field2D&)"); @@ -95,7 +97,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; diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 7d9dda7cea..861ea109c4 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,6 +71,7 @@ Field3D::Field3D(Mesh *localmesh) /// later) Field3D::Field3D(const Field3D &f) : Field(f.fieldmesh), // The mesh containing array sizes + FieldData(f.fieldmesh), background(nullptr), data(f.data), // This handles references to the data array deriv(nullptr), yup_field(nullptr), ydown_field(nullptr) { @@ -100,8 +101,8 @@ 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.getMesh()), background(nullptr), + deriv(nullptr), yup_field(nullptr), ydown_field(nullptr) { TRACE("Field3D: Copy constructor from Field2D"); @@ -118,8 +119,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"); diff --git a/src/field/field_data.cxx b/src/field/field_data.cxx index 6ab19709c7..48c48e4847 100644 --- a/src/field/field_data.cxx +++ b/src/field/field_data.cxx @@ -6,8 +6,11 @@ #include #include "unused.hxx" -FieldData::FieldData() : boundaryIsCopy(false), boundaryIsSet(true) { - +FieldData::FieldData(Mesh* m) : + fielddatamesh(m), boundaryIsCopy(false), boundaryIsSet(true) { + if (fielddatamesh == nullptr) { + fielddatamesh = mesh; + } } FieldData::~FieldData() { @@ -24,7 +27,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 +35,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 +50,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 +79,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/vector2d.cxx b/src/field/vector2d.cxx index 541715b15b..cdaf62dbd1 100644 --- a/src/field/vector2d.cxx +++ b/src/field/vector2d.cxx @@ -36,11 +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(f.getLocation()) {} + : 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) { @@ -148,6 +149,8 @@ Vector2D* Vector2D::timeDeriv() { /////////////////// ASSIGNMENT //////////////////// Vector2D & Vector2D::operator=(const Vector2D &rhs) { + fielddatamesh = rhs.fielddatamesh; + x = rhs.x; y = rhs.y; z = rhs.z; diff --git a/src/field/vector3d.cxx b/src/field/vector3d.cxx index 000e5e0fec..aaaca9c411 100644 --- a/src/field/vector3d.cxx +++ b/src/field/vector3d.cxx @@ -37,11 +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(f.getLocation()) {} + : 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) { @@ -149,6 +150,8 @@ Vector3D* Vector3D::timeDeriv() { /////////////////// ASSIGNMENT //////////////////// Vector3D & Vector3D::operator=(const Vector3D &rhs) { + fielddatamesh = rhs.fielddatamesh; + x = rhs.x; y = rhs.y; z = rhs.z; @@ -160,6 +163,8 @@ Vector3D & Vector3D::operator=(const Vector3D &rhs) { } Vector3D & Vector3D::operator=(const Vector2D &rhs) { + fielddatamesh = rhs.x.getMesh(); + x = rhs.x; y = rhs.y; z = rhs.z; From 2f80b551f2adbd783588534535cccf9839811585 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 15 Oct 2018 17:37:54 +0100 Subject: [PATCH 03/45] Make FieldData() backward compatible, no virtual on getDataMesh() Give default argument 'Mesh* m = nullptr' for FieldData::FieldData constructor so that it is backward compatible. Method FieldData::getDataMesh() does not need to be virtual, since it is unlikely to be overridden. --- include/field_data.hxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/field_data.hxx b/include/field_data.hxx index d75e89c2ca..ac43cfc5f4 100644 --- a/include/field_data.hxx +++ b/include/field_data.hxx @@ -62,13 +62,13 @@ class FieldVisitor; */ class FieldData { public: - FieldData(Mesh* m); + FieldData(Mesh* m = nullptr); virtual ~FieldData(); // Visitor pattern support virtual void accept(FieldVisitor &v) = 0; - virtual Mesh * getDataMesh() const{ + Mesh * getDataMesh() const{ if (fielddatamesh){ return fielddatamesh; } else { From ed767768a4f00679ee3e652ced7526e155d32dc9 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 16 Oct 2018 12:11:41 +0100 Subject: [PATCH 04/45] Move FieldData::fielddatamesh init into init list Also move FieldData ctor into header --- include/field_data.hxx | 11 +++++++---- src/field/field_data.cxx | 7 ------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/include/field_data.hxx b/include/field_data.hxx index ac43cfc5f4..5124726a92 100644 --- a/include/field_data.hxx +++ b/include/field_data.hxx @@ -62,14 +62,17 @@ class FieldVisitor; */ class FieldData { public: - FieldData(Mesh* m = nullptr); + 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){ + + Mesh *getDataMesh() const { + if (fielddatamesh != nullptr) { return fielddatamesh; } else { return mesh; diff --git a/src/field/field_data.cxx b/src/field/field_data.cxx index 48c48e4847..98bf71eaec 100644 --- a/src/field/field_data.cxx +++ b/src/field/field_data.cxx @@ -6,13 +6,6 @@ #include #include "unused.hxx" -FieldData::FieldData(Mesh* m) : - fielddatamesh(m), boundaryIsCopy(false), boundaryIsSet(true) { - if (fielddatamesh == nullptr) { - fielddatamesh = mesh; - } -} - FieldData::~FieldData() { if(!boundaryIsCopy) { // Delete the boundary operations From 95e2ff21faee1ce3f003ae306e1f5ed59f940855 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 16 Oct 2018 12:27:15 +0100 Subject: [PATCH 05/45] Check Mesh*'s are the same in Field3D operator=(Field2D) --- src/field/field3d.cxx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 861ea109c4..0d55a9e9c4 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -313,10 +313,12 @@ Field3D & Field3D::operator=(const Field3D &rhs) { Field3D & Field3D::operator=(const Field2D &rhs) { TRACE("Field3D = Field2D"); + + ASSERT1(fieldmesh == rhs.getMesh()); /// Check that the data is valid checkData(rhs); - + /// Make sure there's a unique array to copy data into allocate(); From c6adde39370766f8909fb93e55de6d4cee42b4cb Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 16 Oct 2018 12:28:01 +0100 Subject: [PATCH 06/45] Copy or check fielddatamesh in Field3D/Field2D operator= --- src/field/field2d.cxx | 1 + src/field/field3d.cxx | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index 0346179738..e98dc21eaa 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -203,6 +203,7 @@ Field2D &Field2D::operator=(const Field2D &rhs) { // Copy the data and data sizes fieldmesh = rhs.fieldmesh; + fielddatamesh = rhs.fielddatamesh; nx = rhs.nx; ny = rhs.ny; diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 0d55a9e9c4..2fd0e81e5b 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -302,6 +302,7 @@ Field3D & Field3D::operator=(const Field3D &rhs) { // Copy the data and data sizes fieldmesh = rhs.fieldmesh; + fielddatamesh = rhs.fielddatamesh; nx = rhs.nx; ny = rhs.ny; nz = rhs.nz; data = rhs.data; @@ -315,6 +316,7 @@ Field3D & Field3D::operator=(const Field2D &rhs) { TRACE("Field3D = Field2D"); ASSERT1(fieldmesh == rhs.getMesh()); + ASSERT1(fielddatamesh == rhs.getDataMesh()); /// Check that the data is valid checkData(rhs); From e851da6b691a28c17b36adee60cf159fa070fea3 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 16 Oct 2018 13:35:11 +0100 Subject: [PATCH 07/45] Check consistency of fieldmesh and fielddatamesh In places where fieldmesh and fielddatamesh are set from separate pointers, check that their values are equal. Also, for consistency set fielddatamesh from *.fielddatamesh or *.getDataMesh(), rather than fieldmesh or getMesh(). --- src/field/field2d.cxx | 9 ++++++--- src/field/field3d.cxx | 14 ++++++++++---- src/field/vector3d.cxx | 2 +- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index e98dc21eaa..b228dbfa80 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -67,11 +67,13 @@ Field2D::Field2D(Mesh *localmesh) : } Field2D::Field2D(const Field2D& f) : Field(f.fieldmesh), // The mesh containing array sizes - FieldData(f.fieldmesh), + 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 @@ -202,8 +204,9 @@ Field2D &Field2D::operator=(const Field2D &rhs) { #endif // Copy the data and data sizes - fieldmesh = rhs.fieldmesh; - fielddatamesh = rhs.fielddatamesh; + 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 2fd0e81e5b..99c963674b 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -71,12 +71,14 @@ Field3D::Field3D(Mesh *localmesh) /// later) Field3D::Field3D(const Field3D &f) : Field(f.fieldmesh), // The mesh containing array sizes - FieldData(f.fieldmesh), + 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 @@ -101,11 +103,13 @@ Field3D::Field3D(const Field3D &f) } Field3D::Field3D(const Field2D &f) - : Field(f.getMesh()), FieldData(f.getMesh()), background(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; @@ -301,8 +305,9 @@ Field3D & Field3D::operator=(const Field3D &rhs) { checkData(rhs); // Copy the data and data sizes - fieldmesh = rhs.fieldmesh; - fielddatamesh = rhs.fielddatamesh; + 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; @@ -317,6 +322,7 @@ Field3D & Field3D::operator=(const Field2D &rhs) { 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); diff --git a/src/field/vector3d.cxx b/src/field/vector3d.cxx index aaaca9c411..e7d254f205 100644 --- a/src/field/vector3d.cxx +++ b/src/field/vector3d.cxx @@ -163,7 +163,7 @@ Vector3D & Vector3D::operator=(const Vector3D &rhs) { } Vector3D & Vector3D::operator=(const Vector2D &rhs) { - fielddatamesh = rhs.x.getMesh(); + fielddatamesh = rhs.x.getDataMesh(); x = rhs.x; y = rhs.y; From ea904ba88ec4fcaffd499c5d06158934535a65ee Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 17 Oct 2018 18:51:01 +0100 Subject: [PATCH 08/45] Move mesh checks after allocate() In Field3D::operator=(Field2D) move the checks on fieldmesh consistency to after the call to allocate(). If fields were declared in global scope and therefore initialized with a null Mesh*, fieldmesh may not be set to a sensible value until allocate() has been called. --- src/field/field3d.cxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 99c963674b..f9e7db3dc6 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -320,16 +320,16 @@ 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(); + ASSERT1(fieldmesh == rhs.getMesh()); + ASSERT1(fielddatamesh == rhs.getDataMesh()); + ASSERT1(fieldmesh == fielddatamesh); // Check consistency between Field::fieldmesh and FieldData::fielddatamesh + /// Copy data const Region ®ion_all = fieldmesh->getRegion3D("RGN_ALL"); From 8a07c7eac8efcdba4fe126e4f26fd444344e51ec Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 17 Oct 2018 18:54:22 +0100 Subject: [PATCH 09/45] Set fielddatamesh in Field2D/Field3D::allocate() If fieldmesh needs to be set, so will fielddatamesh. Therefore set it to global mesh in allocate() if fieldmesh is being set. --- src/field/field2d.cxx | 1 + src/field/field3d.cxx | 1 + 2 files changed, 2 insertions(+) diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index b228dbfa80..a2ad23dd58 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -120,6 +120,7 @@ void Field2D::allocate() { if(!fieldmesh) { /// If no mesh, use the global fieldmesh = mesh; + fielddatamesh = mesh; nx = fieldmesh->LocalNx; ny = fieldmesh->LocalNy; } diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index f9e7db3dc6..5e5f4b9d16 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -164,6 +164,7 @@ void Field3D::allocate() { if(!fieldmesh) { /// If no mesh, use the global fieldmesh = mesh; + fielddatamesh = mesh; nx = fieldmesh->LocalNx; ny = fieldmesh->LocalNy; nz = fieldmesh->LocalNz; From af75612dd5aaf45dfcd27311cbf6bb0a0d605db0 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 11 Oct 2018 20:52:05 +0100 Subject: [PATCH 10/45] Refactor boundary conditions code Put most of the functionality into the base BoundaryOp class, removing copy-paste code from boundary_standard.cxx. Use some templates to further shorten code. --- include/boundary_factory.hxx | 34 +- include/boundary_op.hxx | 87 +- include/boundary_region.hxx | 43 +- include/boundary_standard.hxx | 308 +-- include/parallel_boundary_op.hxx | 26 +- include/parallel_boundary_region.hxx | 22 +- src/field/field3d.cxx | 10 +- src/field/field_data.cxx | 4 +- src/mesh/boundary_factory.cxx | 126 +- src/mesh/boundary_op.cxx | 266 +++ src/mesh/boundary_standard.cxx | 3149 +++++--------------------- src/mesh/makefile | 12 +- 12 files changed, 1209 insertions(+), 2878 deletions(-) create mode 100644 src/mesh/boundary_op.cxx diff --git a/include/boundary_factory.hxx b/include/boundary_factory.hxx index e4c6a67d55..e59fb681cf 100644 --- a/include/boundary_factory.hxx +++ b/include/boundary_factory.hxx @@ -14,6 +14,12 @@ class BoundaryFactory; using std::string; using std::map; +template +using BoundaryOpRegion = typename std::conditional::value, BoundaryRegionPar, BoundaryRegion>::type; + +template +using BoundaryRegionOp = typename std::conditional::value, BoundaryOpPar, BoundaryOp>::type; + /// Create BoundaryOp objects on demand /*! * This implements a simple string parser, used to match boundary condition @@ -55,7 +61,7 @@ using std::map; * Subsequent calls to create() or createFromOptions() can make use * of the boundary type "myboundary". * - * BoundaryOpBase *bndry = bf->create("myboundary()", new BoundaryRegionXOut("xout", 0, 10, localmesh)); + * BoundaryOp *bndry = bf->create("myboundary()", new BoundaryRegionXOut("xout", 0, 10, localmesh)); * * where the region is defined in boundary_region.hxx * @@ -69,12 +75,16 @@ class BoundaryFactory { static void cleanup(); ///< Frees all memory /// Create a boundary operation object - BoundaryOpBase* create(const string &name, BoundaryRegionBase *region); - BoundaryOpBase* create(const char* name, BoundaryRegionBase *region); + template + BoundaryRegionOp* create(const string &name, T* region); + template + BoundaryRegionOp* create(const char* name, T* region); /// Create a boundary object using the options file - BoundaryOpBase* createFromOptions(const string &varname, BoundaryRegionBase *region); - BoundaryOpBase* createFromOptions(const char* varname, BoundaryRegionBase *region); + template + BoundaryRegionOp* createFromOptions(const string &varname, T* region); + template + BoundaryRegionOp* createFromOptions(const char* varname, T* region); /*! * Add available boundary conditions and modifiers @@ -119,14 +129,18 @@ class BoundaryFactory { // map par_modmap; // Functions to look up operations and modifiers - BoundaryOp* findBoundaryOp(const string &s); + // Standard or parallel boundary conditions + template + T* findBoundaryOp(const string &s); + // Boundary modifiers BoundaryModifier* findBoundaryMod(const string &s); - // Parallel boundary conditions - BoundaryOpPar* findBoundaryOpPar(const string &s); - // To be implemented... - // BoundaryModifier* findBoundaryMod(const string &s); }; +template<> +BoundaryOp* BoundaryFactory::findBoundaryOp(const string &s); +template<> +BoundaryOpPar* BoundaryFactory::findBoundaryOp(const string &s); + #endif // __BNDRY_FACTORY_H__ diff --git a/include/boundary_op.hxx b/include/boundary_op.hxx index 5a15fd21ff..a10173d804 100644 --- a/include/boundary_op.hxx +++ b/include/boundary_op.hxx @@ -18,16 +18,29 @@ class BoundaryModifier; using std::string; using std::list; -class BoundaryOpBase { +/// An operation on a boundary +class BoundaryOp { public: - BoundaryOpBase() {} - virtual ~BoundaryOpBase() {} + BoundaryOp() : bndry(nullptr), apply_to_ddt(false), gen(nullptr) {} + BoundaryOp(BoundaryRegion *region) + : bndry(region), apply_to_ddt(false), gen(nullptr) {} + BoundaryOp(BoundaryRegion *region, std::shared_ptr g) + : bndry(region), apply_to_ddt(false), gen(std::move(g)) {} + virtual ~BoundaryOp() {} + + // Note: All methods must implement clone, except for modifiers (see below) + virtual BoundaryOp* clone(BoundaryRegion *UNUSED(region), const list &UNUSED(args)) { + ASSERT1(false); // this implementation should never get called + return nullptr; + } /// Apply a boundary condition on field f - virtual void apply(Field2D &f) = 0; - virtual void apply(Field2D &f,BoutReal UNUSED(t)){return apply(f);}//JMAD - virtual void apply(Field3D &f) = 0; - virtual void apply(Field3D &f,BoutReal UNUSED(t)){return apply(f);}//JMAD + virtual void apply(Field2D &f,BoutReal t = 0.) { + applyTemplate(f, t); + } + virtual void apply(Field3D &f,BoutReal t = 0.) { + applyTemplate(f, t); + } virtual void apply(Vector2D &f) { apply(f.x); @@ -40,30 +53,10 @@ public: apply(f.y); apply(f.z); } -}; - -/// An operation on a boundary -class BoundaryOp : public BoundaryOpBase { -public: - BoundaryOp() { - bndry = nullptr; - apply_to_ddt = false; - } - BoundaryOp(BoundaryRegion *region) {bndry = region; apply_to_ddt=false;} - ~BoundaryOp() override {} - - // Note: All methods must implement clone, except for modifiers (see below) - virtual BoundaryOp* clone(BoundaryRegion *UNUSED(region), const list &UNUSED(args)) { - return nullptr; - } /// Apply a boundary condition on ddt(f) - virtual void apply_ddt(Field2D &f) { - apply(ddt(f)); - } - virtual void apply_ddt(Field3D &f) { - apply(ddt(f)); - } + virtual void apply_ddt(Field2D &f); + virtual void apply_ddt(Field3D &f); virtual void apply_ddt(Vector2D &f) { apply(ddt(f)); } @@ -73,6 +66,41 @@ public: BoundaryRegion *bndry; bool apply_to_ddt; // True if this boundary condition should be applied on the time derivatives, false if it should be applied to the field values + +protected: + std::shared_ptr gen; // Generator + + // Apply boundary condition at a point + virtual void applyAtPoint(Field2D &UNUSED(f), BoutReal UNUSED(val), int + UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), + Coordinates* UNUSED(metric)) { + ASSERT1(false); + } + virtual void applyAtPoint(Field3D &UNUSED(f), BoutReal UNUSED(val), int + UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), + Coordinates* UNUSED(metric)) { + ASSERT1(false); + } + + // Apply to staggered grid + virtual void applyAtPointStaggered(Field2D &UNUSED(f), BoutReal UNUSED(val), + int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int + UNUSED(z), Coordinates* UNUSED(metric)) { + ASSERT1(false); + } + virtual void applyAtPointStaggered(Field3D &UNUSED(f), BoutReal UNUSED(val), + int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int + UNUSED(z), Coordinates* UNUSED(metric)) { + ASSERT1(false); + } + + // extrapolate to further guard cells + virtual void extrapFurther(Field2D &f, int x, int bx, int y, int by, int z); + virtual void extrapFurther(Field3D &f, int x, int bx, int y, int by, int z); + +private: + template + void applyTemplate(T &f, BoutReal t); }; class BoundaryModifier : public BoundaryOp { @@ -80,6 +108,7 @@ public: BoundaryModifier() : op(nullptr) {} BoundaryModifier(BoundaryOp *operation) : BoundaryOp(operation->bndry), op(operation) {} virtual BoundaryOp* cloneMod(BoundaryOp *op, const list &args) = 0; + virtual BoundaryOpPar* cloneMod(BoundaryOpPar *UNUSED(op), const list &UNUSED(args)) { throw BoutException("BoundaryModifier should not be called on a BoundaryOpPar."); } protected: BoundaryOp *op; }; diff --git a/include/boundary_region.hxx b/include/boundary_region.hxx index 0121fc4c64..bf616293cc 100644 --- a/include/boundary_region.hxx +++ b/include/boundary_region.hxx @@ -20,23 +20,30 @@ enum BndryLoc {BNDRY_XIN=1, BNDRY_PAR_FWD=16, // Don't include parallel boundaries BNDRY_PAR_BKWD=32}; -class BoundaryRegionBase { +/// Describes a region of the boundary, and a means of iterating over it +class BoundaryRegion { public: - - BoundaryRegionBase() = delete; - BoundaryRegionBase(std::string name, Mesh *passmesh = nullptr) - : localmesh(passmesh ? passmesh : mesh), label(std::move(name)) {} - BoundaryRegionBase(std::string name, BndryLoc loc, Mesh *passmesh = nullptr) + BoundaryRegion() = delete; + BoundaryRegion(std::string name, BndryLoc loc, Mesh *passmesh = nullptr) : localmesh(passmesh ? passmesh : mesh), label(std::move(name)), location(loc) {} + BoundaryRegion(std::string name, int xd, int yd, Mesh *passmesh = nullptr) + : bx(xd), by(yd), width(2), localmesh(passmesh ? passmesh : mesh), label(std::move(name)) {} + virtual ~BoundaryRegion() {} - virtual ~BoundaryRegionBase() {} + int x,y; ///< Indices of the point in the boundary + int bx, by; ///< Direction of the boundary [x+dx][y+dy] is going outwards + + int width; ///< Width of the boundary + + virtual void next1d() = 0; ///< Loop over the innermost elements + virtual void nextX() = 0; ///< Just loop over X + virtual void nextY() = 0; ///< Just loop over Y Mesh* localmesh; ///< Mesh does this boundary region belongs to string label; ///< Label for this boundary region BndryLoc location; ///< Which side of the domain is it on? - bool isParallel = false; ///< Is this a parallel boundary? virtual void first() = 0; ///< Move the region iterator to the start virtual void next() = 0; ///< Get the next element in the loop @@ -45,26 +52,6 @@ public: virtual bool isDone() = 0; ///< Returns true if outside domain. Can use this with nested nextX, nextY }; -/// Describes a region of the boundary, and a means of iterating over it -class BoundaryRegion : public BoundaryRegionBase { -public: - BoundaryRegion() = delete; - BoundaryRegion(std::string name, BndryLoc loc, Mesh *passmesh = nullptr) - : BoundaryRegionBase(name, loc, passmesh) {} - BoundaryRegion(std::string name, int xd, int yd, Mesh *passmesh = nullptr) - : BoundaryRegionBase(name, passmesh), bx(xd), by(yd), width(2) {} - ~BoundaryRegion() override {} - - int x,y; ///< Indices of the point in the boundary - int bx, by; ///< Direction of the boundary [x+dx][y+dy] is going outwards - - int width; ///< Width of the boundary - - virtual void next1d() = 0; ///< Loop over the innermost elements - virtual void nextX() = 0; ///< Just loop over X - virtual void nextY() = 0; ///< Just loop over Y -}; - class BoundaryRegionXIn : public BoundaryRegion { public: BoundaryRegionXIn(std::string name, int ymin, int ymax, Mesh* passmesh = nullptr); diff --git a/include/boundary_standard.hxx b/include/boundary_standard.hxx index ca9a05fc11..6a7769057f 100644 --- a/include/boundary_standard.hxx +++ b/include/boundary_standard.hxx @@ -10,44 +10,23 @@ #include -/// Dirichlet boundary condition set half way between guard cell and grid cell at 2nd order accuracy -class BoundaryDirichlet_2ndOrder : public BoundaryOp { - public: - BoundaryDirichlet_2ndOrder() : val(0.) {} - BoundaryDirichlet_2ndOrder(BoutReal setval ): val(setval) {} - BoundaryDirichlet_2ndOrder(BoundaryRegion *region, BoutReal setval=0.):BoundaryOp(region),val(setval) { } - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; - - using BoundaryOp::apply; - void apply(Field2D &f) override; - void apply(Field3D &f) override; - - using BoundaryOp::apply_ddt; - void apply_ddt(Field2D &f) override; - void apply_ddt(Field3D &f) override; - private: - BoutReal val; -}; - /// Dirichlet (set to zero) boundary condition class BoundaryDirichlet : public BoundaryOp { public: - BoundaryDirichlet() : gen(nullptr) {} - BoundaryDirichlet(BoundaryRegion *region, std::shared_ptr g) - : BoundaryOp(region), gen(std::move(g)) {} + using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors BoundaryOp* clone(BoundaryRegion *region, const list &args) override; using BoundaryOp::apply; - void apply(Field2D &f) override; - void apply(Field2D &f,BoutReal t) override; - void apply(Field3D &f) override; - void apply(Field3D &f,BoutReal t) override; + void apply(Field2D &f,BoutReal t = 0.) override { + applyTemplate(f, t); + } + void apply(Field3D &f,BoutReal t = 0.) override { + applyTemplate(f, t); + } - using BoundaryOp::apply_ddt; - void apply_ddt(Field2D &f) override; - void apply_ddt(Field3D &f) override; private: - std::shared_ptr gen; // Generator + template + void applyTemplate(T &f, BoutReal t); }; BoutReal default_func(BoutReal t, int x, int y, int z); @@ -55,62 +34,55 @@ BoutReal default_func(BoutReal t, int x, int y, int z); /// 3nd-order boundary condition class BoundaryDirichlet_O3 : public BoundaryOp { public: - BoundaryDirichlet_O3() : gen(nullptr) {} - BoundaryDirichlet_O3(BoundaryRegion *region, std::shared_ptr g) - : BoundaryOp(region), gen(std::move(g)) {} + using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors BoundaryOp* clone(BoundaryRegion *region, const list &args) override; - using BoundaryOp::apply; - void apply(Field2D &f) override; - void apply(Field2D &f,BoutReal t) override; - void apply(Field3D &f) override; - void apply(Field3D &f,BoutReal t) override; - - using BoundaryOp::apply_ddt; - void apply_ddt(Field2D &f) override; - void apply_ddt(Field3D &f) override; - private: - std::shared_ptr gen; // Generator + void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) override; + void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) override; + void extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) override; + void extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) override; }; /// 4th-order boundary condition class BoundaryDirichlet_O4 : public BoundaryOp { public: - BoundaryDirichlet_O4() : gen(nullptr) {} - BoundaryDirichlet_O4(BoundaryRegion *region, std::shared_ptr g) - : BoundaryOp(region), gen(std::move(g)) {} + using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors BoundaryOp* clone(BoundaryRegion *region, const list &args) override; - using BoundaryOp::apply; - void apply(Field2D &f) override; - void apply(Field2D &f,BoutReal t) override; - void apply(Field3D &f) override; - void apply(Field3D &f,BoutReal t) override; + void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) override; + void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) override; + void extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) override; + void extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) override; +}; - using BoundaryOp::apply_ddt; - void apply_ddt(Field2D &f) override; - void apply_ddt(Field3D &f) override; - private: - std::shared_ptr gen; // Generator +/// Dirichlet boundary condition set half way between guard cell and grid cell at 2nd order accuracy +class BoundaryDirichlet_2ndOrder : public BoundaryOp { + public: + using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors + BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + + void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) override; + void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) override; }; /// Dirichlet boundary condition set half way between guard cell and grid cell at 4th order accuracy class BoundaryDirichlet_4thOrder : public BoundaryOp { public: - BoundaryDirichlet_4thOrder() : val(0.) {} - BoundaryDirichlet_4thOrder(BoutReal setval ): val(setval) {} - BoundaryDirichlet_4thOrder(BoundaryRegion *region, BoutReal setval=0.):BoundaryOp(region),val(setval) { } + using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors BoundaryOp* clone(BoundaryRegion *region, const list &args) override; - using BoundaryOp::apply; - void apply(Field2D &f) override; - void apply(Field3D &f) override; - - using BoundaryOp::apply_ddt; - void apply_ddt(Field2D &f) override; - void apply_ddt(Field3D &f) override; - private: - BoutReal val; + void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) override; + void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) override; + void extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) override; + void extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) override; }; /// Neumann (zero-gradient) boundary condition for non-orthogonal meshes @@ -122,141 +94,128 @@ class BoundaryNeumann_NonOrthogonal : public BoundaryOp { BoundaryOp* clone(BoundaryRegion *region, const list &args) override; using BoundaryOp::apply; - void apply(Field2D &f) override; - void apply(Field3D &f) override; + void apply(Field2D &f, BoutReal t = 0.) override { + applyTemplate(f, t); + } + void apply(Field3D &f, BoutReal t = 0.) override { + applyTemplate(f, t); + } private: BoutReal val; + + template + void applyTemplate(T &f, BoutReal t); }; /// Neumann (zero-gradient) boundary condition, using 2nd order on boundary class BoundaryNeumann2 : public BoundaryOp { public: - BoundaryNeumann2() {} - BoundaryNeumann2(BoundaryRegion *region):BoundaryOp(region) { } + using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors BoundaryOp* clone(BoundaryRegion *region, const list &args) override; - using BoundaryOp::apply; - void apply(Field2D &f) override; - void apply(Field3D &f) override; + void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; }; /// Neumann boundary condition set half way between guard cell and grid cell at 2nd order accuracy class BoundaryNeumann_2ndOrder : public BoundaryOp { public: - BoundaryNeumann_2ndOrder() : val(0.) {} - BoundaryNeumann_2ndOrder(BoutReal setval ): val(setval) {} - BoundaryNeumann_2ndOrder(BoundaryRegion *region, BoutReal setval=0.):BoundaryOp(region),val(setval) { } + using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors BoundaryOp* clone(BoundaryRegion *region, const list &args) override; - using BoundaryOp::apply; - void apply(Field2D &f) override; - void apply(Field3D &f) override; - - using BoundaryOp::apply_ddt; - void apply_ddt(Field2D &f) override; - void apply_ddt(Field3D &f) override; - private: - BoutReal val; + void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; }; // Neumann boundary condition set half way between guard cell and grid cell at 2nd order accuracy class BoundaryNeumann : public BoundaryOp { public: - BoundaryNeumann() : gen(nullptr) {} - BoundaryNeumann(BoundaryRegion *region, std::shared_ptr g) - : BoundaryOp(region), gen(std::move(g)) {} + using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors BoundaryOp* clone(BoundaryRegion *region, const list &args) override; - using BoundaryOp::apply; - void apply(Field2D &f) override; - void apply(Field2D &f, BoutReal t) override; - void apply(Field3D &f) override; - void apply(Field3D &f,BoutReal t) override; - - using BoundaryOp::apply_ddt; - void apply_ddt(Field2D &f) override; - void apply_ddt(Field3D &f) override; - private: - std::shared_ptr gen; + void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; + void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; + void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; }; /// Neumann boundary condition set half way between guard cell and grid cell at 4th order accuracy -class BoundaryNeumann_4thOrder : public BoundaryOp { +class BoundaryNeumann_O4 : public BoundaryOp { public: - BoundaryNeumann_4thOrder() : val(0.) {} - BoundaryNeumann_4thOrder(BoutReal setval ): val(setval) {} - BoundaryNeumann_4thOrder(BoundaryRegion *region, BoutReal setval=0.):BoundaryOp(region),val(setval) { } + using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors BoundaryOp* clone(BoundaryRegion *region, const list &args) override; - using BoundaryOp::apply; - void apply(Field2D &f) override; - void apply(Field3D &f) override; - - using BoundaryOp::apply_ddt; - void apply_ddt(Field2D &f) override; - void apply_ddt(Field3D &f) override; - private: - BoutReal val; + void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; + void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; + void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + void extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) override; + void extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) override; }; /// Neumann boundary condition set half way between guard cell and grid cell at 4th order accuracy -class BoundaryNeumann_O4 : public BoundaryOp { +class BoundaryNeumann_4thOrder : public BoundaryOp { public: - BoundaryNeumann_O4() : gen(nullptr) {} - BoundaryNeumann_O4(BoundaryRegion *region, std::shared_ptr g) - : BoundaryOp(region), gen(std::move(g)) {} + using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors BoundaryOp* clone(BoundaryRegion *region, const list &args) override; - using BoundaryOp::apply; - void apply(Field2D &f) override; - void apply(Field2D &f, BoutReal t) override; - void apply(Field3D &f) override; - void apply(Field3D &f,BoutReal t) override; - - using BoundaryOp::apply_ddt; - void apply_ddt(Field2D &f) override; - void apply_ddt(Field3D &f) override; - private: - std::shared_ptr gen; + void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; + void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; + void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + void extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) override; + void extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) override; }; /// NeumannPar (zero-gradient) boundary condition on /// the variable / sqrt(g_22) class BoundaryNeumannPar : public BoundaryOp { public: - BoundaryNeumannPar() {} - BoundaryNeumannPar(BoundaryRegion *region):BoundaryOp(region) { } + using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors BoundaryOp* clone(BoundaryRegion *region, const list &args) override; - using BoundaryOp::apply; - void apply(Field2D &f) override; - void apply(Field3D &f) override; + void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; + void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; + void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; }; /// Robin (mix of Dirichlet and Neumann) class BoundaryRobin : public BoundaryOp { public: BoundaryRobin() : aval(0.), bval(0.), gval(0.) {} - BoundaryRobin(BoundaryRegion *region, BoutReal a, BoutReal b, BoutReal g):BoundaryOp(region), aval(a), bval(b), gval(g) { } + BoundaryRobin(BoundaryRegion *region, BoutReal a, BoutReal b, BoutReal g) + : BoundaryOp(region), aval(a), bval(b), gval(g) { } BoundaryOp* clone(BoundaryRegion *region, const list &args) override; using BoundaryOp::apply; - void apply(Field2D &f) override; - void apply(Field3D &f) override; + void apply(Field2D &f, BoutReal t = 0.) override { + applyTemplate(f, t); + } + void apply(Field3D &f, BoutReal t = 0.) override { + applyTemplate(f, t); + } private: BoutReal aval, bval, gval; + + template + void applyTemplate(T &f, BoutReal t); }; /// Constant gradient (zero second derivative) class BoundaryConstGradient : public BoundaryOp { public: - BoundaryConstGradient() {} - BoundaryConstGradient(BoundaryRegion *region):BoundaryOp(region) { } + using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors BoundaryOp* clone(BoundaryRegion *region, const list &args) override; - using BoundaryOp::apply; - void apply(Field2D &f) override; - void apply(Field3D &f) override; + void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; }; /// Zero Laplacian, decaying solution @@ -267,8 +226,8 @@ class BoundaryZeroLaplace : public BoundaryOp { BoundaryOp* clone(BoundaryRegion *region, const list &args) override; using BoundaryOp::apply; - void apply(Field2D &f) override; - void apply(Field3D &f) override; + void apply(Field2D &f, BoutReal UNUSED(t)) override; + void apply(Field3D &f, BoutReal UNUSED(t)) override; }; /// Zero Laplacian @@ -279,8 +238,8 @@ class BoundaryZeroLaplace2 : public BoundaryOp { BoundaryOp* clone(BoundaryRegion *region, const list &args) override; using BoundaryOp::apply; - void apply(Field2D &f) override; - void apply(Field3D &f) override; + void apply(Field2D &f, BoutReal t) override; + void apply(Field3D &f, BoutReal t) override; }; /// Constant Laplacian, decaying solution @@ -291,8 +250,8 @@ class BoundaryConstLaplace : public BoundaryOp { BoundaryOp* clone(BoundaryRegion *region, const list &args) override; using BoundaryOp::apply; - void apply(Field2D &f) override; - void apply(Field3D &f) override; + void apply(Field2D &f, BoutReal t) override; + void apply(Field3D &f, BoutReal t) override; }; /// Vector boundary condition Div(B) = 0, Curl(B) = 0 @@ -303,8 +262,8 @@ class BoundaryDivCurl : public BoundaryOp { BoundaryOp* clone(BoundaryRegion *region, const list &args) override; using BoundaryOp::apply; - void apply(Field2D &UNUSED(f)) override { throw BoutException("ERROR: DivCurl boundary only for vectors"); } - void apply(Field3D &UNUSED(f)) override { throw BoutException("ERROR: DivCurl boundary only for vectors"); } + void apply(Field2D &UNUSED(f), BoutReal UNUSED(t)) override { throw BoutException("ERROR: DivCurl boundary only for vectors"); } + void apply(Field3D &UNUSED(f), BoutReal UNUSED(t)) override { throw BoutException("ERROR: DivCurl boundary only for vectors"); } void apply(Vector2D &f) override; void apply(Vector3D &f) override; }; @@ -312,14 +271,12 @@ class BoundaryDivCurl : public BoundaryOp { /// Free boundary condition (evolve the field in the guard cells, using non-centred derivatives to calculate the ddt) class BoundaryFree : public BoundaryOp { public: - BoundaryFree() : val(0.) {apply_to_ddt = true;} - BoundaryFree(BoutReal setval): val(setval) {} - BoundaryFree(BoundaryRegion *region, BoutReal setval=0.):BoundaryOp(region),val(setval) { } + using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors BoundaryOp* clone(BoundaryRegion *region, const list &args) override; using BoundaryOp::apply; - void apply(Field2D &f) override; - void apply(Field3D &f) override; + void apply(Field2D &f, BoutReal UNUSED(t)) override; + void apply(Field3D &f, BoutReal UNUSED(t)) override; using BoundaryOp::apply_ddt; void apply_ddt(Field2D &f) override; @@ -332,33 +289,26 @@ class BoundaryFree : public BoundaryOp { /// Alternative free boundary condition (evolve the field in the guard cells, using non-centred derivatives to calculate the ddt) class BoundaryFree_O2 : public BoundaryOp { public: - BoundaryFree_O2() {} - BoundaryFree_O2(BoundaryRegion *region):BoundaryOp(region) { } + using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors BoundaryOp* clone(BoundaryRegion *region, const list &args) override; - using BoundaryOp::apply; - void apply(Field2D &f) override; - void apply(Field3D &f) override; - - using BoundaryOp::apply_ddt; - void apply_ddt(Field2D &f) override; - void apply_ddt(Field3D &f) override; + void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; }; class BoundaryFree_O3 : public BoundaryOp { public: - BoundaryFree_O3() {} - BoundaryFree_O3(BoundaryRegion *region):BoundaryOp(region) { } + using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors BoundaryOp* clone(BoundaryRegion *region, const list &args) override; - using BoundaryOp::apply; - void apply(Field2D &f) override; - void apply(Field3D &f) override; - - using BoundaryOp::apply_ddt; - void apply_ddt(Field2D &f) override; - void apply_ddt(Field3D &f) override; - + void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; + void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; + void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + void extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) override; + void extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) override; }; // End L.Easy @@ -373,9 +323,7 @@ class BoundaryRelax : public BoundaryModifier { BoundaryOp* cloneMod(BoundaryOp *op, const list &args) override; using BoundaryModifier::apply; - void apply(Field2D &f) override {apply(f, 0.);}; void apply(Field2D &f, BoutReal t) override; - void apply(Field3D &f) override {apply(f, 0.);}; void apply(Field3D &f, BoutReal t) override; using BoundaryModifier::apply_ddt; @@ -393,9 +341,7 @@ public: BoundaryOp* cloneMod(BoundaryOp *op, const list &args) override; using BoundaryModifier::apply; - void apply(Field2D &f) override {apply(f, 0.);}; void apply(Field2D &f, BoutReal t) override; - void apply(Field3D &f) override {apply(f, 0.);}; void apply(Field3D &f, BoutReal t) override; using BoundaryModifier::apply_ddt; @@ -414,9 +360,7 @@ public: BoundaryOp* cloneMod(BoundaryOp *op, const list &args) override; using BoundaryModifier::apply; - void apply(Field2D &f) override {apply(f, 0.);}; void apply(Field2D &f, BoutReal t) override; - void apply(Field3D &f) override {apply(f, 0.);}; void apply(Field3D &f, BoutReal t) override; using BoundaryModifier::apply_ddt; @@ -434,9 +378,7 @@ public: BoundaryOp* cloneMod(BoundaryOp *op, const list &args) override; using BoundaryModifier::apply; - void apply(Field2D &f) override {apply(f, 0.);}; void apply(Field2D &f, BoutReal t) override; - void apply(Field3D &f) override {apply(f, 0.);}; void apply(Field3D &f, BoutReal t) override; using BoundaryModifier::apply_ddt; diff --git a/include/parallel_boundary_op.hxx b/include/parallel_boundary_op.hxx index 3bd0be5c15..dca96399f6 100644 --- a/include/parallel_boundary_op.hxx +++ b/include/parallel_boundary_op.hxx @@ -12,7 +12,7 @@ ////////////////////////////////////////////////// // Base class -class BoundaryOpPar : public BoundaryOpBase { +class BoundaryOpPar { public: BoundaryOpPar() : bndry(nullptr), real_value(0.), value_type(REAL) {} BoundaryOpPar(BoundaryRegionPar *region, std::shared_ptr value) @@ -25,18 +25,28 @@ public: bndry(region), real_value(value), value_type(REAL) {} - ~BoundaryOpPar() override {} + virtual ~BoundaryOpPar() {} // Note: All methods must implement clone, except for modifiers (see below) virtual BoundaryOpPar* clone(BoundaryRegionPar *UNUSED(region), const list &UNUSED(args)) {return nullptr; } virtual BoundaryOpPar* clone(BoundaryRegionPar *UNUSED(region), Field3D *UNUSED(f)) {return nullptr; } - using BoundaryOpBase::apply; - void apply(Field2D &UNUSED(f)) override { + /// Apply a boundary condition on field f + virtual void apply(Field3D &f,BoutReal t = 0.) = 0; + void apply(Field2D &UNUSED(f), BoutReal UNUSED(t) = 0.) { throw BoutException("Can't apply parallel boundary conditions to Field2D!"); } - void apply(Field2D &UNUSED(f), BoutReal UNUSED(t)) override { - throw BoutException("Can't apply parallel boundary conditions to Field2D!"); + + virtual void apply(Vector2D &f) { + apply(f.x); + apply(f.y); + apply(f.z); + } + + virtual void apply(Vector3D &f) { + apply(f.x); + apply(f.y); + apply(f.z); } BoundaryRegionPar *bndry; @@ -75,7 +85,6 @@ public: BoundaryOpPar* clone(BoundaryRegionPar *region, Field3D *f) override; using BoundaryOpPar::apply; - void apply(Field3D &f) override {return apply(f, 0);} void apply(Field3D &f, BoutReal t) override; }; @@ -95,7 +104,6 @@ public: BoundaryOpPar* clone(BoundaryRegionPar *region, Field3D *f) override; using BoundaryOpPar::apply; - void apply(Field3D &f) override {return apply(f, 0);} void apply(Field3D &f, BoutReal t) override; }; @@ -115,7 +123,6 @@ public: BoundaryOpPar* clone(BoundaryRegionPar *region, Field3D *f) override; using BoundaryOpPar::apply; - void apply(Field3D &f) override {return apply(f, 0);} void apply(Field3D &f, BoutReal t) override; }; @@ -135,7 +142,6 @@ public: BoundaryOpPar* clone(BoundaryRegionPar *region, Field3D *f) override; using BoundaryOpPar::apply; - void apply(Field3D &f) override {return apply(f, 0);} void apply(Field3D &f, BoutReal t) override; }; diff --git a/include/parallel_boundary_region.hxx b/include/parallel_boundary_region.hxx index 2025ad9abb..827e563735 100644 --- a/include/parallel_boundary_region.hxx +++ b/include/parallel_boundary_region.hxx @@ -10,7 +10,7 @@ * inside the boundary. * */ -class BoundaryRegionPar : public BoundaryRegionBase { +class BoundaryRegionPar { struct IndexPoint { int jx; @@ -45,20 +45,26 @@ class BoundaryRegionPar : public BoundaryRegionBase { public: BoundaryRegionPar(const string &name, int dir, Mesh* passmesh) : - BoundaryRegionBase(name, passmesh), dir(dir) { - BoundaryRegionBase::isParallel = true;} + localmesh(passmesh ? passmesh : mesh), label(std::move(name)), dir(dir) {} BoundaryRegionPar(const string &name, BndryLoc loc,int dir, Mesh* passmesh) : - BoundaryRegionBase(name, loc, passmesh), dir(dir) { - BoundaryRegionBase::isParallel = true;} + localmesh(passmesh ? passmesh : mesh), label(std::move(name)), location(loc), dir(dir) {} /// Add a point to the boundary void add_point(int jx,int jy,int jz, const BoutReal x,BoutReal y,BoutReal z, const BoutReal length,BoutReal angle); - void first() override; - void next() override; - bool isDone() override; + void first(); ///< Move the region iterator to the start + void next(); ///< Get the next element in the loop + /// over every element from inside out (in + /// X or Y first) + bool isDone(); ///< Returns true if outside domain. Can use this with nested nextX, nextY + + Mesh* localmesh; ///< Mesh does this boundary region belongs to + + string label; ///< Label for this boundary region + + BndryLoc location; ///< Which side of the domain is it on? /// Index of the point in the boundary int x, y, z; diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 5e5f4b9d16..125dc2454d 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -454,7 +454,7 @@ void Field3D::applyBoundary(const string &condition) { /// Loop over the mesh boundary regions for(const auto& reg : fieldmesh->getBoundaries()) { - BoundaryOp* op = static_cast(bfact->create(condition, reg)); + BoundaryOp* op = bfact->create(condition, reg); op->apply(*this); delete op; } @@ -474,7 +474,7 @@ void Field3D::applyBoundary(const string ®ion, const string &condition) { for (const auto ® : fieldmesh->getBoundaries()) { if (reg->label.compare(region) == 0) { region_found = true; - BoundaryOp *op = static_cast(bfact->create(condition, reg)); + BoundaryOp *op = bfact->create(condition, reg); op->apply(*this); delete op; break; @@ -581,7 +581,7 @@ void Field3D::applyParallelBoundary(const string &condition) { /// Loop over the mesh boundary regions for(const auto& reg : fieldmesh->getBoundariesPar()) { - BoundaryOpPar* op = static_cast(bfact->create(condition, reg)); + BoundaryOpPar* op = bfact->create(condition, reg); op->apply(*this); delete op; } @@ -606,7 +606,7 @@ void Field3D::applyParallelBoundary(const string ®ion, const string &conditio /// Loop over the mesh boundary regions for(const auto& reg : fieldmesh->getBoundariesPar()) { if(reg->label.compare(region) == 0) { - BoundaryOpPar* op = static_cast(bfact->create(condition, reg)); + BoundaryOpPar* op = bfact->create(condition, reg); op->apply(*this); delete op; break; @@ -635,7 +635,7 @@ void Field3D::applyParallelBoundary(const string ®ion, const string &conditio if(reg->label.compare(region) == 0) { // BoundaryFactory can't create boundaries using Field3Ds, so get temporary // boundary of the right type - BoundaryOpPar* tmp = static_cast(bfact->create(condition, reg)); + BoundaryOpPar* tmp = bfact->create(condition, reg); // then clone that with the actual argument BoundaryOpPar* op = tmp->clone(reg, f); op->apply(*this); diff --git a/src/field/field_data.cxx b/src/field/field_data.cxx index 98bf71eaec..982626a362 100644 --- a/src/field/field_data.cxx +++ b/src/field/field_data.cxx @@ -21,7 +21,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 : getDataMesh()->getBoundaries()) { - BoundaryOp* op = static_cast(bfact->createFromOptions(name, reg)); + BoundaryOp* op = bfact->createFromOptions(name, reg); if (op != nullptr) bndry_op.push_back(op); output_info << endl; @@ -31,7 +31,7 @@ void FieldData::setBoundary(const string &name) { vector par_reg = getDataMesh()->getBoundariesPar(); /// Loop over the mesh parallel boundary regions for(const auto& reg : getDataMesh()->getBoundariesPar()) { - BoundaryOpPar* op = static_cast(bfact->createFromOptions(name, reg)); + BoundaryOpPar* op = bfact->createFromOptions(name, reg); if (op != nullptr) bndry_op_par.push_back(op); output_info << endl; diff --git a/src/mesh/boundary_factory.cxx b/src/mesh/boundary_factory.cxx index 86a617e2fd..2ddf87c23a 100644 --- a/src/mesh/boundary_factory.cxx +++ b/src/mesh/boundary_factory.cxx @@ -23,7 +23,7 @@ BoundaryFactory::BoundaryFactory() { add(new BoundaryNeumann(), "neumann_O2"); // Synonym for "neumann" add(new BoundaryNeumann2(), "neumann2"); // Deprecated add(new BoundaryNeumann_2ndOrder(), "neumann_2ndorder"); // Deprecated - add(new BoundaryNeumann_4thOrder(), "neumann_4thorder"); + add(new BoundaryNeumann_4thOrder(), "neumann_4thorder"); // Deprecated: Less good version of neumann_O4 add(new BoundaryNeumann_O4(), "neumann_O4"); add(new BoundaryNeumannPar(), "neumannpar"); add(new BoundaryNeumann_NonOrthogonal(), "neumann_nonorthogonal"); @@ -78,7 +78,8 @@ void BoundaryFactory::cleanup() { instance = nullptr; } -BoundaryOpBase* BoundaryFactory::create(const string &name, BoundaryRegionBase *region) { +template +BoundaryRegionOp* BoundaryFactory::create(const string &name, T* region) { // Search for a string of the form: modifier(operation) auto pos = name.find('('); @@ -89,26 +90,16 @@ BoundaryOpBase* BoundaryFactory::create(const string &name, BoundaryRegionBase * if( (name == "null") || (name == "none") ) return nullptr; - if(region->isParallel) { - // Parallel boundary - BoundaryOpPar *pop = findBoundaryOpPar(trim(name)); - if (pop == nullptr) - throw BoutException("Could not find parallel boundary condition '%s'", name.c_str()); - - // Clone the boundary operation, passing the region to operate over and an empty args list - list args; - return pop->clone(static_cast(region), args); - } else { - // Perpendicular boundary - BoundaryOp *op = findBoundaryOp(trim(name)); - if (op == nullptr) - throw BoutException("Could not find boundary condition '%s'", name.c_str()); - - // Clone the boundary operation, passing the region to operate over and an empty args list - list args; - return op->clone(static_cast(region), args); + BoundaryRegionOp *op = findBoundaryOp< BoundaryRegionOp >(trim(name)); + if (op == nullptr) { + throw BoutException("Could not find boundary condition '%s'", name.c_str()); } + + // Clone the boundary operation, passing the region to operate over and an empty args list + list args; + return op->clone(region, args); } + // Contains a bracket. Find the last bracket and remove auto pos2 = name.rfind(')'); if(pos2 == string::npos) { @@ -158,34 +149,34 @@ BoundaryOpBase* BoundaryFactory::create(const string &name, BoundaryRegionBase * } */ - // Test if func is a modifier - BoundaryModifier *mod = findBoundaryMod(func); - if (mod != nullptr) { - // The first argument should be an operation - BoundaryOp *op = static_cast(create(arglist.front(), region)); - if (op == nullptr) - return nullptr; + if (std::is_same, BoundaryOp>::value) { + // Test if func is a modifier + BoundaryModifier *mod = findBoundaryMod(func); + if (mod != nullptr) { + // The first argument should be an operation + BoundaryRegionOp *op = create(arglist.front(), region); + if (op == nullptr) { + return nullptr; + } - // Remove the first element (name of operation) - arglist.pop_front(); + // Remove the first element (name of operation) + arglist.pop_front(); - // Clone the modifier, passing in the operator and remaining strings as argument - return mod->cloneMod(op, arglist); - } + // Clone the modifier, passing in the operator and remaining strings as argument + return mod->cloneMod(op, arglist); + } - if(region->isParallel) { - // Parallel boundary - BoundaryOpPar *pop = findBoundaryOpPar(trim(func)); - if (pop != nullptr) { + BoundaryRegionOp *op = findBoundaryOp< BoundaryRegionOp >(trim(func)); + if (op != nullptr) { // An operation with arguments - return pop->clone(static_cast(region), arglist); + return op->clone(region, arglist); } } else { - // Perpendicular boundary - BoundaryOp *op = findBoundaryOp(trim(func)); - if (op != nullptr) { + // Parallel boundary + BoundaryRegionOp *pop = findBoundaryOp< BoundaryRegionOp >(trim(func)); + if (pop != nullptr) { // An operation with arguments - return op->clone(static_cast(region), arglist); + return pop->clone(region, arglist); } } @@ -195,11 +186,19 @@ BoundaryOpBase* BoundaryFactory::create(const string &name, BoundaryRegionBase * return nullptr; } -BoundaryOpBase* BoundaryFactory::create(const char* name, BoundaryRegionBase *region) { +template +BoundaryRegionOp* BoundaryFactory::create(const char* name, T* region) { return create(string(name), region); } - -BoundaryOpBase* BoundaryFactory::createFromOptions(const string &varname, BoundaryRegionBase *region) { +// const char* version calls the string version, so this should instantiate +// both: +template +BoundaryOp* BoundaryFactory::create(const char* name, BoundaryRegion* region); +template +BoundaryOpPar* BoundaryFactory::create(const char* name, BoundaryRegionPar* region); + +template +BoundaryRegionOp* BoundaryFactory::createFromOptions(const string &varname, T* region) { if (region == nullptr) return nullptr; @@ -259,7 +258,7 @@ BoundaryOpBase* BoundaryFactory::createFromOptions(const string &varname, Bounda } /// Then (var, all) - if(region->isParallel) { + if(std::is_same, BoundaryOpPar>::value) { if(varOpts->isSet(prefix+"par_all")) { varOpts->get(prefix+"par_all", set, ""); return create(set, region); @@ -287,7 +286,7 @@ BoundaryOpBase* BoundaryFactory::createFromOptions(const string &varname, Bounda } /// Then (all, all) - if(region->isParallel) { + if(std::is_same, BoundaryOpPar>::value) { // Different default for parallel boundary regions varOpts->get(prefix+"par_all", set, "parallel_dirichlet"); } else { @@ -298,12 +297,19 @@ BoundaryOpBase* BoundaryFactory::createFromOptions(const string &varname, Bounda // values. If a user want to override, specify "none" or "null" } -BoundaryOpBase* BoundaryFactory::createFromOptions(const char* varname, BoundaryRegionBase *region) { +template +BoundaryRegionOp* BoundaryFactory::createFromOptions(const char* varname, T* region) { return createFromOptions(string(varname), region); } +// const char* version calls the string version, so this should instantiate +// both: +template +BoundaryOp* BoundaryFactory::createFromOptions(const char* name, BoundaryRegion* region); +template +BoundaryOpPar* BoundaryFactory::createFromOptions(const char* name, BoundaryRegionPar* region); void BoundaryFactory::add(BoundaryOp* bop, const string &name) { - if ((findBoundaryMod(name) != nullptr) || (findBoundaryOp(name) != nullptr)) { + if ((findBoundaryMod(name) != nullptr) || (findBoundaryOp(name) != nullptr)) { // error - already exists output_error << "ERROR: Trying to add an already existing boundary: " << name << endl; return; @@ -316,7 +322,7 @@ void BoundaryFactory::add(BoundaryOp* bop, const char *name) { } void BoundaryFactory::add(BoundaryOpPar* bop, const string &name) { - if (findBoundaryOpPar(name) != nullptr) { + if (findBoundaryOp(name) != nullptr) { // error - already exists output_error << "ERROR: Trying to add an already existing boundary: " << name << endl; return; @@ -329,7 +335,7 @@ void BoundaryFactory::add(BoundaryOpPar* bop, const char *name) { } void BoundaryFactory::addMod(BoundaryModifier* bmod, const string &name) { - if ((findBoundaryMod(name) != nullptr) || (findBoundaryOp(name) != nullptr)) { + if ((findBoundaryMod(name) != nullptr) || (findBoundaryOp(name) != nullptr)) { // error - already exists output_error << "ERROR: Trying to add an already existing boundary modifier: " << name << endl; return; @@ -341,7 +347,8 @@ void BoundaryFactory::addMod(BoundaryModifier* bmod, const char *name) { addMod(bmod, string(name)); } -BoundaryOp* BoundaryFactory::findBoundaryOp(const string &s) { +template<> +BoundaryOp* BoundaryFactory::findBoundaryOp(const string &s) { map::iterator it; it = opmap.find(lowercase(s)); if(it == opmap.end()) @@ -349,18 +356,19 @@ BoundaryOp* BoundaryFactory::findBoundaryOp(const string &s) { return it->second; } -BoundaryModifier* BoundaryFactory::findBoundaryMod(const string &s) { - map::iterator it; - it = modmap.find(lowercase(s)); - if(it == modmap.end()) +template<> +BoundaryOpPar* BoundaryFactory::findBoundaryOp(const string &s) { + map::iterator it; + it = par_opmap.find(lowercase(s)); + if(it == par_opmap.end()) return nullptr; return it->second; } -BoundaryOpPar* BoundaryFactory::findBoundaryOpPar(const string &s) { - map::iterator it; - it = par_opmap.find(lowercase(s)); - if(it == par_opmap.end()) +BoundaryModifier* BoundaryFactory::findBoundaryMod(const string &s) { + map::iterator it; + it = modmap.find(lowercase(s)); + if(it == modmap.end()) return nullptr; return it->second; } diff --git a/src/mesh/boundary_op.cxx b/src/mesh/boundary_op.cxx new file mode 100644 index 0000000000..e6f05b2b40 --- /dev/null +++ b/src/mesh/boundary_op.cxx @@ -0,0 +1,266 @@ +/*************************************************************************** + * Copyright 2018 B.D. Dudson, J.T. Omotani + * + * Contact: Ben Dudson, bd512@york.ac.uk + * + * This file is part of BOUT++. + * + * BOUT++ is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * BOUT++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with BOUT++. If not, see . + * + **************************************************************************/ + +#include +#include +#include + +void BoundaryOp::extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) { + f(x, y, z) = 2.0*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z); +} +void BoundaryOp::extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) { + f(x, y, z) = 2.0*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z); +} + +template +void BoundaryOp::applyTemplate(T &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(); + Coordinates* metric = f.getCoordinates(); + + // Check for staggered grids + CELL_LOC loc = f.getLocation(); + + bndry->first(); + + // Decide which generator to use + std::shared_ptr fg = gen; + if(!fg) { + fg = f.getBndryGenerator(bndry->location); + } + + BoutReal val = 0.0; + + if (loc == CELL_CENTRE) { + // no staggering + 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 + + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) // In the guard cell + + localmesh->GlobalY(bndry->y - bndry->by) ); // the grid cell + + for(int z=0; zGlobalZ(z); + if (fg) { + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + } + applyAtPoint(f, val, bndry->x, bndry->bx, bndry->y, bndry->by, z, metric); + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for (int i = 1; i < bndry->width; i++) { + int x = bndry->x + i*bndry->bx; + int y = bndry->y + i*bndry->by; + extrapFurther(f, x, bndry->bx, y, bndry->by, z); + } + } + } + } 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 z=0; zGlobalZ(z); + if(fg){ + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + } + applyAtPointStaggered(f, val, bndry->x, bndry->bx, bndry->y, 0, z, metric); + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for (int i = 1; i < bndry->width; i++) { + int x = bndry->x + i*bndry->bx; + extrapFurther(f, x, bndry->bx, bndry->y, 0, z); + } + } + } + } + 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 z=0; zGlobalZ(z); + if(fg){ + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + } + // Set one point inwards + applyAtPointStaggered(f, val, bndry->x + 1, bndry->bx, bndry->y, 0, z, metric); + + // Need to set second and third guard cells, as may be used for interpolation or upwinding derivatives + for (int i = 0; i < bndry->width; i++) { + int x = bndry->x + i*bndry->bx; + extrapFurther(f, x, bndry->bx, bndry->y, 0, z); + } + } + } + } + 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 z=0; zGlobalZ(z); + if(fg){ + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + } + applyAtPoint(f, val, bndry->x, 0, bndry->y, bndry->by, z, metric); + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=1;iwidth;i++) { + int y = bndry->y + i*bndry->by; + extrapFurther(f, bndry->x, 0, y, bndry->by, z); + } + } + } + } + } 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 z=0; zGlobalZ(z); + if(fg){ + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + } + applyAtPointStaggered(f, val, bndry->x, 0, bndry->y, bndry->by, z, metric); + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=1;iwidth;i++) { + int y = bndry->y + i*bndry->by; + extrapFurther(f, bndry->x, 0, y, bndry->by, z); + } + } + } + } + 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 z=0; zGlobalZ(z); + if(fg){ + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + } + applyAtPointStaggered(f, val, bndry->x, 0, bndry->y+1, bndry->by, z, metric); + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=0;iwidth;i++) { + int y = bndry->y + i*bndry->by; + extrapFurther(f, bndry->x, 0, y, bndry->by, z); + } + } + } + } + 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 z=0; zGlobalZ(z); + if(fg) { + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + } + + applyAtPoint(f, val, bndry->x, bndry->bx, bndry->y, 0, z, metric); + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=1;iwidth;i++) { + int x = bndry->x + i*bndry->bx; + extrapFurther(f, x, bndry->bx, bndry->y, 0, z); + } + } + } + } + } else if ( loc == CELL_ZLOW ){ + // Staggered in Z. Note there are no z-boundaries. + 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 + + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) // In the guard cell + + localmesh->GlobalY(bndry->y - bndry->by) ); // the grid cell + + for(int z=0; zgenerate should be periodic in z + BoutReal znorm = 0.5*( localmesh->GlobalZ(z) + localmesh->GlobalZ(z - 1) ); // znorm is shifted by half a grid point because it is staggered + if (fg) { + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + } + applyAtPoint(f, val, bndry->x, bndry->bx, bndry->y, bndry->by, z, metric); + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for (int i = 1; i < bndry->width; i++) { + int x = bndry->x + i*bndry->bx; + int y = bndry->y + i*bndry->by; + extrapFurther(f, x, bndry->bx, y, bndry->by, z); + } + } + } + } +} +//// instantiate template for Field2D and Field3D +//template +//void BoundaryOp::applyTemplate(Field2D &f,BoutReal t); +//template +//void BoundaryOp::applyTemplate(Field3D &f,BoutReal t); + +void BoundaryOp::apply_ddt(Field2D &f) { + Field2D *dt = f.timeDeriv(); + for(bndry->first(); !bndry->isDone(); bndry->next()) + for(int z=0; zx, bndry->y, z) = 0.; // Set time derivative to zero +} + +void BoundaryOp::apply_ddt(Field3D &f) { + Field3D *dt = f.timeDeriv(); + for(bndry->first(); !bndry->isDone(); bndry->next()) + for(int z=0; zx, bndry->y, z) = 0.; // Set time derivative to zero +} diff --git a/src/mesh/boundary_standard.cxx b/src/mesh/boundary_standard.cxx index 44f910d74d..c6209b64b6 100644 --- a/src/mesh/boundary_standard.cxx +++ b/src/mesh/boundary_standard.cxx @@ -9,8 +9,6 @@ #include #include -// #define BOUNDARY_CONDITIONS_UPGRADE_EXTRAPOLATE_FOR_2ND_ORDER - /////////////////////////////////////////////////////////////// // Helpers @@ -23,90 +21,94 @@ 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"; - - //Here 2*mesh->xstart is the total number of guard/boundary cells - ptsAvailGlobal = mesh->GlobalNx - 2*mesh->xstart; - - //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; - - //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"; - } + Mesh* localmesh = region->localmesh; - break; - } - case BNDRY_YUP: - case BNDRY_YDOWN: { - side = "y"; - - //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 = 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"; + 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"; + + //Here 2*localmesh->xstart is the total number of guard/boundary cells + ptsAvailGlobal = localmesh->GlobalNx - 2*localmesh->xstart; + + //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; + + //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; + std::shared_ptr newgen = nullptr; if(!args.empty()) { // First argument should be an expression newgen = FieldFactory::get()->parse(args.front()); @@ -114,382 +116,46 @@ BoundaryOp* BoundaryDirichlet::clone(BoundaryRegion *region, const list return new BoundaryDirichlet(region, newgen); } -void BoundaryDirichlet::apply(Field2D &f){ - BoundaryDirichlet::apply(f,0.); -} - -void BoundaryDirichlet::apply(Field2D &f,BoutReal t) { +// Override apply(), using this private method to provide both Field2D and +// Field3D versions, for BoundaryDirichlet because we apply a funny hack to the +// extra guard cells +template +void BoundaryDirichlet::applyTemplate(T &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 - - bndry->first(); - - // Decide which generator to use - std::shared_ptr fg = gen; - if(!fg) - fg = f.getBndryGenerator(bndry->location); - BoutReal val = 0.0; - + 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 ) { - // 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; - - // 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->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); - } - } - } - } - 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) { - // 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 ; - 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); - } - } - } - } - } else { - // Non-staggered, standard case - - 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); - } - - 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); - } - } - } -} - - -void BoundaryDirichlet::apply(Field3D &f) { - BoundaryDirichlet::apply(f,0.); -} - -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 + ASSERT1(localmesh->StaggerGrids || loc == CELL_CENTRE); bndry->first(); // Decide which generator to use std::shared_ptr fg = gen; - if(!fg) + 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 - - 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 (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->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){ - // 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); - } - } - } - } - 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 (loc == CELL_CENTRE) { + // Unstaggered case 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; zkGlobalZ(zk); + if(fg){ + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, 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,454 +191,238 @@ 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; zkGlobalZ(zk); if(fg) { - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(mesh->LocalNz), t); + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); } f(xi, yi, zk) = val; } } } - } -} + } else 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; zkGlobalZ(zk); + if(fg){ + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, 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 ; -void BoundaryDirichlet::apply_ddt(Field2D &f) { - Field2D *dt = f.timeDeriv(); - for(bndry->first(); !bndry->isDone(); bndry->next()) - (*dt)(bndry->x,bndry->y) = 0.; // Set time derivative to zero -} + 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; zkGlobalZ(zk); + if(fg){ + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + } + f(bndry->x - bndry->bx,bndry->y, zk) = val; -void BoundaryDirichlet::apply_ddt(Field3D &f) { - Field3D *dt = f.timeDeriv(); - for(bndry->first(); !bndry->isDone(); bndry->next()) - for(int z=0;zLocalNz;z++) - (*dt)(bndry->x,bndry->y,z) = 0.; // Set time derivative to zero -} + // 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*( 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; zkGlobalZ(zk); + if(fg){ + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + } + f(bndry->x,bndry->y,zk) = 2*val - f(bndry->x-bndry->bx, bndry->y-bndry->by, zk); -/////////////////////////////////////////////////////////////// -// New implementation, accurate to higher order + // 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; -BoundaryOp* BoundaryDirichlet_O3::clone(BoundaryRegion *region, const list &args){ - verifyNumPoints(region,2); - std::shared_ptr newgen = nullptr; - if(!args.empty()) { - // First argument should be an expression - newgen = FieldFactory::get()->parse(args.front()); - } - return new BoundaryDirichlet_O3(region, newgen); -} + 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; zkGlobalZ(zk); + if(fg){ + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + } + f(bndry->x,bndry->y,zk) = val; -void BoundaryDirichlet_O3::apply(Field2D &f){ - BoundaryDirichlet_O3::apply(f,0.); -} + // 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; -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 - - bndry->first(); + f(xi, yi, zk) = 2.0*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()) { - // Decide which generator to use - std::shared_ptr fg = gen; - if(!fg) - fg = f.getBndryGenerator(bndry->location); + BoutReal xnorm = localmesh->GlobalX(bndry->x); + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) + localmesh->GlobalY(bndry->y - bndry->by) ); - BoutReal val = 0.0; - + for(int zk=0; zkGlobalZ(zk); + if(fg){ + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + } + f(bndry->x,bndry->y - bndry->by, zk) = val; - // 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(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->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); - } - - } + // 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 ) { - // 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); - } - - } - } - 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->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; zkGlobalZ(zk); + if(fg) { + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + } - } - } - 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); - } - } + 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 { - // Non-staggered, standard case - + } else if (loc == CELL_ZLOW) { + // Staggered in Z. Note there are no z-boundaries. 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 + + for(int zk=0; zkgenerate should be periodic in z + BoutReal znorm = 0.5*( localmesh->GlobalZ(zk) + localmesh->GlobalZ(zk - 1) ); // znorm is shifted by half a grid point because it is staggered + if(fg){ + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, 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); + } } - - 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); - } } } } +/////////////////////////////////////////////////////////////// +// New implementation, accurate to higher order -void BoundaryDirichlet_O3::apply(Field3D &f) { - BoundaryDirichlet_O3::apply(f,0.); -} +BoundaryOp* BoundaryDirichlet_O3::clone(BoundaryRegion *region, const list &args){ + verifyNumPoints(region, 2); + std::shared_ptr newgen = nullptr; + if(!args.empty()) { + // First argument should be an expression + newgen = FieldFactory::get()->parse(args.front()); + } + return new BoundaryDirichlet_O3(region, newgen); +} -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 +void BoundaryDirichlet_O3::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = (8./3)*val - 2.*f(x - bx, y - by, z) + f(x - 2*bx, y - 2*by, z)/3.; +} +void BoundaryDirichlet_O3::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = (8./3)*val - 2.*f(x - bx, y - by, z) + f(x - 2*bx, y - 2*by, z)/3.; +} - 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 - - 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(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->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); - } - } - } - } - } - 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); - } - } - } - } - 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->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); - } - } - } - } - } - } - else { - // Standard (non-staggered) case - 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 - - 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); - } - } - } - } +void BoundaryDirichlet_O3::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = val; } - -void BoundaryDirichlet_O3::apply_ddt(Field2D &f) { - Field2D *dt = f.timeDeriv(); - for(bndry->first(); !bndry->isDone(); bndry->next()) - (*dt)(bndry->x,bndry->y) = 0.; // Set time derivative to zero +void BoundaryDirichlet_O3::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = val; } -void BoundaryDirichlet_O3::apply_ddt(Field3D &f) { - Field3D *dt = f.timeDeriv(); - - bndry->first() ; - for(bndry->first(); !bndry->isDone(); bndry->next()){ - for(int z=0;zLocalNz;z++){ - (*dt)(bndry->x,bndry->y,z) = 0.; // Set time derivative to zero - } - } +void BoundaryDirichlet_O3::extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) { + f(x, y, z) = 3.0*f(x - bx, y - by, z) - 3.0*f(x - 2*bx, y - 2*by, z) + f(x - 3*bx, y - 3*by, z); +} +void BoundaryDirichlet_O3::extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) { + f(x, y, z) = 3.0*f(x - bx, y - by, z) - 3.0*f(x - 2*bx, y - 2*by, z) + f(x - 3*bx, y - 3*by, z); } /////////////////////////////////////////////////////////////// // 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 @@ -981,419 +431,27 @@ BoundaryOp* BoundaryDirichlet_O4::clone(BoundaryRegion *region, const listfirst(); - - // 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 - - 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(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->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); - } - } - } - } - 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); - } - } - } - 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; - - // 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); - } - } - } - } - } - else { - // Non-staggered, standard case - - 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); - } - - 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); - } - } - } +void BoundaryDirichlet_O4::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = (16./5)*val - 3.*f(x - bx, y - by, z) + f(x - 2*bx, y - 2*by, z) - (1./5)*f(x - 3*bx, y - 3*by, z); } - -void BoundaryDirichlet_O4::apply(Field3D &f) { - BoundaryDirichlet_O4::apply(f,0.); +void BoundaryDirichlet_O4::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = val; } - - -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 - - 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 - - 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(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->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); - } - } - } - } - } - 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); - } - } - } - } - 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->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); - } - } - } - } - } - } - else { - // Standard (non-staggered) case - 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 - - 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); - } - } - } - } +void BoundaryDirichlet_O4::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = val; } -void BoundaryDirichlet_O4::apply_ddt(Field2D &f) { - Field2D *dt = f.timeDeriv(); - for(bndry->first(); !bndry->isDone(); bndry->next()) - (*dt)(bndry->x,bndry->y) = 0.; // Set time derivative to zero +void BoundaryDirichlet_O4::extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) { + f(x, y, z) = 4.0*f(x - bx, y - by, z) - 6.0*f(x - 2*bx, y - 2*by, z) + + 4.0*f(x - 3*bx, y - 3*by, z) - f(x - 4*bx, y - 4*by, z); } - -void BoundaryDirichlet_O4::apply_ddt(Field3D &f) { - Field3D *dt = f.timeDeriv(); - for(bndry->first(); !bndry->isDone(); bndry->next()) - for(int z=0;zLocalNz;z++) - (*dt)(bndry->x,bndry->y,z) = 0.; // Set time derivative to zero +void BoundaryDirichlet_O4::extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) { + f(x, y, z) = 4.0*f(x - bx, y - by, z) - 6.0*f(x - 2*bx, y - 2*by, z) + + 4.0*f(x - 3*bx, y - 3*by, z) - f(x - 4*bx, y - 4*by, z); } /////////////////////////////////////////////////////////////// @@ -1401,103 +459,81 @@ 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); + + std::shared_ptr newgen = nullptr; if(!args.empty()) { - // First argument should be a value - val = stringToReal(args.front()); - return new BoundaryDirichlet_2ndOrder(region, val); + // First argument should be an expression + newgen = FieldFactory::get()->parse(args.front()); } - return new BoundaryDirichlet_2ndOrder(region); + return new BoundaryDirichlet_2ndOrder(region, newgen); } -void BoundaryDirichlet_2ndOrder::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 - for(bndry->first(); !bndry->isDone(); bndry->next1d()) { - f(bndry->x,bndry->y) = 8./3.*val - 2.*f(bndry->x-bndry->bx,bndry->y-bndry->by) + 1./3.*f(bndry->x-2*bndry->bx,bndry->y-2*bndry->by); -#ifdef BOUNDARY_CONDITIONS_UPGRADE_EXTRAPOLATE_FOR_2ND_ORDER - f(bndry->x+bndry->bx,bndry->y+bndry->by) = 3.*f(bndry->x,bndry->y) - 3.*f(bndry->x-bndry->bx,bndry->y-bndry->by) + f(bndry->x-2*bndry->bx,bndry->y-2*bndry->by); -#elif defined(CHECK) - f(bndry->x+bndry->bx,bndry->y+bndry->by) = 1.e60; -#endif - } +// 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 +void BoundaryDirichlet_2ndOrder::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = 8./3.*val - 2.*f(x - bx, y - by, z) + 1./3.*f(x - 2*bx, y - 2*by, z); } - -void BoundaryDirichlet_2ndOrder::apply(Field3D &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 - for(bndry->first(); !bndry->isDone(); bndry->next1d()) - 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); -#elif defined(CHECK) - f(bndry->x+bndry->bx,bndry->y+bndry->by,z) = 1.e60; -#endif - } +void BoundaryDirichlet_2ndOrder::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = 8./3.*val - 2.*f(x - bx, y - by, z) + 1./3.*f(x - 2*bx, y - 2*by, z); } -void BoundaryDirichlet_2ndOrder::apply_ddt(Field2D &f) { - Field2D *dt = f.timeDeriv(); - for(bndry->first(); !bndry->isDone(); bndry->next()) - (*dt)(bndry->x,bndry->y) = 0.; // Set time derivative to zero +void BoundaryDirichlet_2ndOrder::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = val; } - -void BoundaryDirichlet_2ndOrder::apply_ddt(Field3D &f) { - Field3D *dt = f.timeDeriv(); - for(bndry->first(); !bndry->isDone(); bndry->next()) - for(int z=0;zLocalNz;z++) - (*dt)(bndry->x,bndry->y,z) = 0.; // Set time derivative to zero +void BoundaryDirichlet_2ndOrder::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = val; } /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryDirichlet_4thOrder::clone(BoundaryRegion *region, const list &args) { - verifyNumPoints(region,4); + verifyNumPoints(region, 4); + + std::shared_ptr newgen = nullptr; if(!args.empty()) { - // First argument should be a value - val = stringToReal(args.front()); - return new BoundaryDirichlet_4thOrder(region, val); + // First argument should be an expression + newgen = FieldFactory::get()->parse(args.front()); } - return new BoundaryDirichlet_4thOrder(region); + return new BoundaryDirichlet_4thOrder(region, newgen); } -void BoundaryDirichlet_4thOrder::apply(Field2D &f) { - // 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()) { - f(bndry->x,bndry->y) = 128./35.*val - 4.*f(bndry->x-bndry->bx,bndry->y-bndry->by) + 2.*f(bndry->x-2*bndry->bx,bndry->y-2*bndry->by) - 4./3.*f(bndry->x-3*bndry->bx,bndry->y-3*bndry->by) + 1./7.*f(bndry->x-4*bndry->bx,bndry->y-4*bndry->by); - f(bndry->x+bndry->bx,bndry->y+bndry->by) = -128./5.*val + 9.*f(bndry->x,bndry->y) + 18.*f(bndry->x-bndry->bx,bndry->y-bndry->by) -4.*f(bndry->x-2*bndry->bx,bndry->y-2*bndry->by) + 3./5.*f(bndry->x-3*bndry->bx,bndry->y-3*bndry->by); - } +void BoundaryDirichlet_4thOrder::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = 128./35.*val - 4.*f(x - bx, y - by, z) + 2.*f(x - 2*bx, y - 2*by, z) - 4./5.*f(x - 3*bx, y - 3*by, z) + 1./7.*f(x - 4*bx, y - 4*by, z); } - -void BoundaryDirichlet_4thOrder::apply(Field3D &f) { - // 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++) { - 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); - } +void BoundaryDirichlet_4thOrder::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = 128./35.*val - 4.*f(x - bx, y - by, z) + 2.*f(x - 2*bx, y - 2*by, z) - 4./5.*f(x - 3*bx, y - 3*by, z) + 1./7.*f(x - 4*bx, y - 4*by, z); } -void BoundaryDirichlet_4thOrder::apply_ddt(Field2D &f) { - Field2D *dt = f.timeDeriv(); - for(bndry->first(); !bndry->isDone(); bndry->next()) - (*dt)(bndry->x,bndry->y) = 0.; // Set time derivative to zero +void BoundaryDirichlet_4thOrder::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = val; +} +void BoundaryDirichlet_4thOrder::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = val; } -void BoundaryDirichlet_4thOrder::apply_ddt(Field3D &f) { - Field3D *dt = f.timeDeriv(); - for(bndry->first(); !bndry->isDone(); bndry->next()) - for(int z=0;zLocalNz;z++) - (*dt)(bndry->x,bndry->y,z) = 0.; // Set time derivative to zero +void BoundaryDirichlet_4thOrder::extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) { + // Changing this extrapolation to not depend on val, so just using grid point + // values. Not sure if this is the correct order... JTO 16/10/2018 + f(x, y, z) = 5.0*f(x - bx, y - by, z) - 10.0*f(x - 2*bx, y - 2*by, z) + + 10.0*f(x - 3*bx, y - 3*by, z) - 5.0*f(x - 4*bx, y - 4*by, z) + + f(x - 5*bx, y - 5*by, z); +} +void BoundaryDirichlet_4thOrder::extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) { + // Changing this extrapolation to not depend on val, so just using grid point + // values. Not sure if this is the correct order... JTO 16/10/2018 + f(x, y, z) = 5.0*f(x - bx, y - by, z) - 10.0*f(x - 2*bx, y - 2*by, z) + + 10.0*f(x - 3*bx, y - 3*by, z) - 5.0*f(x - 4*bx, y - 4*by, z) + + f(x - 5*bx, y - 5*by, z); } + /////////////////////////////////////////////////////////////// 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"; + output << "WARNING: argument is set to BoundaryNeumann_NonOrthogonal\n"; // First argument should be a value val = stringToReal(args.front()); return new BoundaryNeumann_NonOrthogonal(region, val); @@ -1505,52 +541,14 @@ BoundaryOp* BoundaryNeumann_NonOrthogonal::clone(BoundaryRegion *region, const l return new BoundaryNeumann_NonOrthogonal(region); } -void BoundaryNeumann_NonOrthogonal::apply(Field2D &f) { +template +void BoundaryNeumann_NonOrthogonal::applyTemplate(T &f, BoutReal UNUSED(t)) { + Mesh* localmesh = f.getMesh(); Coordinates *metric = f.getCoordinates(); // Calculate derivatives for metric use - mesh->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()) { - // Interpolate (linearly) metrics to halfway between last cell and boundary cell - BoutReal g11shift = 0.5*(metric->g11(bndry->x,bndry->y) + metric->g11(bndry->x-bndry->bx,bndry->y)); - BoutReal g12shift = 0.5*(metric->g12(bndry->x,bndry->y) + metric->g12(bndry->x-bndry->bx,bndry->y)); - // 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 - BoutReal xshift = g12shift*dfdy(bndry->x-bndry->bx,bndry->y); - - if(bndry->bx != 0 && bndry->by == 0) { - // x boundaries only - BoutReal delta = bndry->bx*metric->dx(bndry->x, bndry->y); - f(bndry->x, bndry->y) = f(bndry->x - bndry->bx, bndry->y) + delta/g11shift*(val - xshift); - if (bndry->bx == 2){ - f(bndry->x + bndry->bx, bndry->y) = f(bndry->x - 2*bndry->bx, bndry->y) + 3.0*delta/g11shift*(val - xshift); - } - } else if(bndry->by != 0 && bndry->bx == 0) { - // y boundaries only - // no need to shift this b/c we want parallel nuemann not theta - BoutReal delta = bndry->by*metric->dy(bndry->x, bndry->y); - f(bndry->x, bndry->y) = f(bndry->x, bndry->y - bndry->by) + delta*val; - if (bndry->width == 2){ - f(bndry->x, bndry->y + bndry->by) = f(bndry->x, bndry->y - 2*bndry->by) + 3.0*delta*val; - } - } else { - // set corners to zero - f(bndry->x, bndry->y) = 0.0; - if (bndry->width == 2){ - f(bndry->x + bndry->bx, bndry->y + bndry->by) = 0.0; - } - } - } -} - -void BoundaryNeumann_NonOrthogonal::apply(Field3D &f) { - Coordinates *metric = f.getCoordinates(); - // Calculate derivatives for metric use - mesh->communicate(f); - Field3D dfdy = DDY(f); - Field3D dfdz = DDZ(f); + localmesh->communicate(f); + T dfdy = DDY(f); + T dfdz = DDZ(f); // Loop over all elements and set equal to the next point in for(bndry->first(); !bndry->isDone(); bndry->next1d()) { // Interpolate (linearly) metrics to halfway between last cell and boundary cell @@ -1560,7 +558,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,23 +592,27 @@ 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); + + std::shared_ptr newgen = nullptr; if(!args.empty()) { output << "WARNING: Ignoring arguments to BoundaryNeumann2\n"; } - return new BoundaryNeumann2(region); + return new BoundaryNeumann2(region, newgen); } -void BoundaryNeumann2::apply(Field2D &f) { - // Loop over all elements and use one-sided differences - for(bndry->first(); !bndry->isDone(); bndry->next()) - f(bndry->x, bndry->y) = (4.*f(bndry->x - bndry->bx, bndry->y - bndry->by) - f(bndry->x - 2*bndry->bx, bndry->y - 2*bndry->by))/3.; +void BoundaryNeumann2::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = (4.*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z))/3.; +} +void BoundaryNeumann2::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = (4.*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z))/3.; } -void BoundaryNeumann2::apply(Field3D &f) { - for(bndry->first(); !bndry->isDone(); bndry->next()) - 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.; +void BoundaryNeumann2::applyAtPointStaggered(Field2D &UNUSED(f), BoutReal UNUSED(val), int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), Coordinates* UNUSED(metric)) { + throw BoutException("BoundaryNeumann2 not implemented for staggered grids"); +} +void BoundaryNeumann2::applyAtPointStaggered(Field3D &UNUSED(f), BoutReal UNUSED(val), int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), Coordinates* UNUSED(metric)) { + throw BoutException("BoundaryNeumann2 not implemented for staggered grids"); } /////////////////////////////////////////////////////////////// @@ -1618,703 +620,196 @@ void BoundaryNeumann2::apply(Field3D &f) { BoundaryOp* BoundaryNeumann_2ndOrder::clone(BoundaryRegion *region, const list &args) { output << "WARNING: Use of boundary condition \"neumann_2ndorder\" is deprecated!\n"; output << " Consider using \"neumann\" instead\n"; -#ifdef BOUNDARY_CONDITIONS_UPGRADE_EXTRAPOLATE_FOR_2ND_ORDER - verifyNumPoints(region,2); -#else - verifyNumPoints(region,1); -#endif - if(!args.empty()) { - // First argument should be a value - val = stringToReal(args.front()); - return new BoundaryNeumann_2ndOrder(region, val); - } - return new BoundaryNeumann_2ndOrder(region); -} - -void BoundaryNeumann_2ndOrder::apply(Field2D &f) { - Coordinates *metric = f.getCoordinates(); - - // Set (at 2nd 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 - // N.B. Only first guard cells (closest to the grid) should ever be used - for(bndry->first(); !bndry->isDone(); bndry->next1d()) { - f(bndry->x,bndry->y) = f(bndry->x-bndry->bx,bndry->y-bndry->by) + val*(bndry->bx*metric->dx(bndry->x,bndry->y)+bndry->by*metric->dy(bndry->x,bndry->y)); -#ifdef BOUNDARY_CONDITIONS_UPGRADE_EXTRAPOLATE_FOR_2ND_ORDER - f(bndry->x+bndry->bx,bndry->y+bndry->by) = 3.*f(bndry->x,bndry->y) - 3.*f(bndry->x-bndry->bx,bndry->y-bndry->by) + f(bndry->x-2*bndry->bx,bndry->y-2*bndry->by); -#elif defined(CHECK) - f(bndry->x+bndry->bx,bndry->y+bndry->by) = 1.e60; -#endif - } -} - -void BoundaryNeumann_2ndOrder::apply(Field3D &f) { - Coordinates *metric = f.getCoordinates(); - // Set (at 2nd 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 - // 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++) { - 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 - 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); -#elif defined(CHECK) - f(bndry->x+bndry->bx,bndry->y+bndry->by,z) = 1.e60; -#endif - } -} - -void BoundaryNeumann_2ndOrder::apply_ddt(Field2D &f) { - Field2D *dt = f.timeDeriv(); - for(bndry->first(); !bndry->isDone(); bndry->next()) - (*dt)(bndry->x,bndry->y) = 0.; // Set time derivative to zero -} - -void BoundaryNeumann_2ndOrder::apply_ddt(Field3D &f) { - Field3D *dt = f.timeDeriv(); - for(bndry->first(); !bndry->isDone(); bndry->next()) - 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); - std::shared_ptr newgen = nullptr; - if(!args.empty()) { - // First argument should be an expression - newgen = FieldFactory::get()->parse(args.front()); - } - return new BoundaryNeumann(region, newgen); -} - -void BoundaryNeumann::apply(Field2D &f) { - BoundaryNeumann::apply(f,0.); -} - - -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 - - 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); - } - } - } - 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->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; - } - } - } - } - 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); - } - } - } - 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->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 - - 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); - } - - 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; - } - } - } -} - - -void BoundaryNeumann::apply(Field3D &f) { - BoundaryNeumann::apply(f,0.); -} - - -void BoundaryNeumann::apply(Field3D &f,BoutReal t) { - 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); - } - } - } - } - 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->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; - } - } - } - } - } - 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); - } - } - } - } - 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->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; - } - } - } - } - } - } - else { - 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*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; - } - } - } - } -} - -void BoundaryNeumann::apply_ddt(Field2D &f) { - Field2D *dt = f.timeDeriv(); - for(bndry->first(); !bndry->isDone(); bndry->next()) - (*dt)(bndry->x,bndry->y) = 0.; // Set time derivative to zero -} + verifyNumPoints(region, 1); -void BoundaryNeumann::apply_ddt(Field3D &f) { - Field3D *dt = f.timeDeriv(); - for(bndry->first(); !bndry->isDone(); bndry->next()) - for(int z=0;zLocalNz;z++) - (*dt)(bndry->x,bndry->y,z) = 0.; // Set time derivative to zero -} - -/////////////////////////////////////////////////////////////// - -BoundaryOp* BoundaryNeumann_O4::clone(BoundaryRegion *region, const list &args){ std::shared_ptr newgen = nullptr; if(!args.empty()) { - // First argument should be an expression - newgen = FieldFactory::get()->parse(args.front()); - } - return new BoundaryNeumann_O4(region, newgen); -} - -void BoundaryNeumann_O4::apply(Field2D &f) { - BoundaryNeumann_O4::apply(f,0.); -} - -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 - 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) { - 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.; - - if (bndry->width == 2){ - throw BoutException("neumann_o4 with a boundary width of 2 not implemented yet"); - } - } + // First argument should be an expression + newgen = FieldFactory::get()->parse(args.front()); } + return new BoundaryNeumann_2ndOrder(region, newgen); } -void BoundaryNeumann_O4::apply(Field3D &f) { - BoundaryNeumann_O4::apply(f,0.); +void BoundaryNeumann_2ndOrder::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { + BoutReal delta = bx*metric->dx(x, y) + by*metric->dy(x, y); + f(x, y, z) = f(x - bx, y - by, z) + val*delta; +} +void BoundaryNeumann_2ndOrder::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { + BoutReal delta = bx*metric->dx(x, y) + by*metric->dy(x, y); + f(x, y, z) = f(x - bx, y - by, z) + val*delta; } -void BoundaryNeumann_O4::apply(Field3D &f,BoutReal t) { - bndry->first(); +void BoundaryNeumann_2ndOrder::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { + BoutReal delta = bx*metric->dx(x, y) + by*metric->dy(x, y); + f(x, y, z) = (4.*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z) + 2.*delta*val)/3.; +} +void BoundaryNeumann_2ndOrder::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { + BoutReal delta = bx*metric->dx(x, y) + by*metric->dy(x, y); + f(x, y, z) = (4.*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z) + 2.*delta*val)/3.; +} - // 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) { - throw BoutException("neumann_o4 not implemented with staggered grid yet"); +BoundaryOp* BoundaryNeumann::clone(BoundaryRegion *region, const list &args){ + verifyNumPoints(region, 1); + + std::shared_ptr newgen = nullptr; + if(!args.empty()) { + // First argument should be an expression + newgen = FieldFactory::get()->parse(args.front()); } - 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 + return new BoundaryNeumann(region, newgen); +} - 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); +void BoundaryNeumann::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { + BoutReal delta = bx*metric->dx(x, y) + by*metric->dy(x, y); + f(x, y, z) = f(x - bx, y - by, z) + delta*val; +} +void BoundaryNeumann::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { + BoutReal delta = bx*metric->dx(x, y) + by*metric->dy(x, y); + f(x, y, z) = f(x - bx, y - by, z) + delta*val; +} - for(int zk=0;zkLocalNz;zk++) { - if(fg){ - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*zk/(mesh->LocalNz),t); - } +// For staggered case need to apply slightly differently Use one-sided +// differencing. Cell is now on the boundary, so use one-sided differencing +void BoundaryNeumann::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { + BoutReal delta = bx*metric->dx(x, y) + by*metric->dy(x, y); + f(x, y, z) = (4.*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z) + 2.*delta*val)/3.; +} +void BoundaryNeumann::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { + BoutReal delta = bx*metric->dx(x, y) + by*metric->dy(x, y); + f(x, y, z) = (4.*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z) + 2.*delta*val)/3.; +} - 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"); - } - } - } +/////////////////////////////////////////////////////////////// + +BoundaryOp* BoundaryNeumann_O4::clone(BoundaryRegion *region, const list &args){ + verifyNumPoints(region, 4); + + std::shared_ptr newgen = nullptr; + if(!args.empty()) { + // First argument should be an expression + newgen = FieldFactory::get()->parse(args.front()); } + return new BoundaryNeumann_O4(region, newgen); } -void BoundaryNeumann_O4::apply_ddt(Field2D &f) { - Field2D *dt = f.timeDeriv(); - for(bndry->first(); !bndry->isDone(); bndry->next()) - (*dt)(bndry->x,bndry->y) = 0.; // Set time derivative to zero +void BoundaryNeumann_O4::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { + BoutReal delta = bx*metric->dx(x, y) + by*metric->dy(x, y); + f(x, y, z) = 12.*delta*val/11. + + ( 17.*f(x - bx, y - by, z) + 9.*f(x - 2*bx, y - 2*by, z) + - 5.*f(x - 3*bx, y - 3*by, z) + f(x - 4*bx, y - 4*by, z))/22.; +} +void BoundaryNeumann_O4::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { + BoutReal delta = bx*metric->dx(x, y) + by*metric->dy(x, y); + f(x, y, z) = 12.*delta*val/11. + + ( 17.*f(x - bx, y - by, z) + 9.*f(x - 2*bx, y - 2*by, z) + - 5.*f(x - 3*bx, y - 3*by, z) + f(x - 4*bx, y - 4*by, z))/22.; } -void BoundaryNeumann_O4::apply_ddt(Field3D &f) { - Field3D *dt = f.timeDeriv(); - for(bndry->first(); !bndry->isDone(); bndry->next()) - for(int z=0;zLocalNz;z++) - (*dt)(bndry->x,bndry->y,z) = 0.; // Set time derivative to zero +void BoundaryNeumann_O4::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { + BoutReal delta = bx*metric->dx(x, y) + by*metric->dy(x, y); + f(x, y, z) = 12./25.*(delta*val + + 4.*f(x - bx, y - by, z) - 3.*f(x - 2*bx, y - 2*by, z) + + 4./3.*f(x - 3*bx, y - 3*by, z) - 1./4.*f(x - 4*bx, y - 4*by, z)); +} +void BoundaryNeumann_O4::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { + BoutReal delta = bx*metric->dx(x, y) + by*metric->dy(x, y); + f(x, y, z) = 12./25.*(delta*val + + 4.*f(x - bx, y - by, z) - 3.*f(x - 2*bx, y - 2*by, z) + + 4./3.*f(x - 3*bx, y - 3*by, z) - 1./4.*f(x - 4*bx, y - 4*by, z)); +} + +void BoundaryNeumann_O4::extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) { + f(x, y, z) = 5.0*f(x - bx, y - by, z) - 10.0*f(x - 2*bx, y - 2*by, z) + + 10.0*f(x - 3*bx, y - 3*by, z) - 5.0*f(x - 4*bx, y - 4*by, z) + + f(x - 5*bx, y - 5*by, z); +} +void BoundaryNeumann_O4::extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) { + f(x, y, z) = 5.0*f(x - bx, y - by, z) - 10.0*f(x - 2*bx, y - 2*by, z) + + 10.0*f(x - 3*bx, y - 3*by, z) - 5.0*f(x - 4*bx, y - 4*by, z) + + f(x - 5*bx, y - 5*by, z); } /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryNeumann_4thOrder::clone(BoundaryRegion *region, const list &args) { - verifyNumPoints(region,4); + verifyNumPoints(region, 4); + + std::shared_ptr newgen = nullptr; if(!args.empty()) { - // First argument should be a value - val = stringToReal(args.front()); - return new BoundaryNeumann_4thOrder(region, val); + // First argument should be an expression + newgen = FieldFactory::get()->parse(args.front()); } - return new BoundaryNeumann_4thOrder(region); + return new BoundaryNeumann_4thOrder(region, newgen); } -void BoundaryNeumann_4thOrder::apply(Field2D &f) { - 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()) { - BoutReal delta = -(bndry->bx*metric->dx(bndry->x,bndry->y)+bndry->by*metric->dy(bndry->x,bndry->y)); - f(bndry->x,bndry->y) = 12.*delta/11.*val + 17./22.*f(bndry->x-bndry->bx,bndry->y-bndry->by) + 9./22.*f(bndry->x-2*bndry->bx,bndry->y-2*bndry->by) - 5./22.*f(bndry->x-3*bndry->bx,bndry->y-3*bndry->by) + 1./22.*f(bndry->x-4*bndry->bx,bndry->y-4*bndry->by); - f(bndry->x+bndry->bx,bndry->y+bndry->by) = -24.*delta*val + 27.*f(bndry->x,bndry->y) - 27.*f(bndry->x-bndry->bx,bndry->y-bndry->by) + f(bndry->x-2*bndry->bx,bndry->y-2*bndry->by); // The f(bndry->x-4*bndry->bx,bndry->y-4*bndry->by) 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 - } +void BoundaryNeumann_4thOrder::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { + BoutReal delta = -(bx*metric->dx(x, y) + by*metric->dy(x, y)); + f(x, y, z) = 12.*delta/11.*val + 17./22.*f(x - bx, y - by, z) + 9./22.*f(x - 2*bx, y - 2*by, z) - 5./22.*f(x - 3*bx, y - 3*by, z) + 1./22.*f(x - 4*bx, y - 4*by, z); } - -void BoundaryNeumann_4thOrder::apply(Field3D &f) { - 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++) { - 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 - } +void BoundaryNeumann_4thOrder::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { + BoutReal delta = -(bx*metric->dx(x, y) + by*metric->dy(x, y)); + f(x, y, z) = 12.*delta/11.*val + 17./22.*f(x - bx, y - by, z) + 9./22.*f(x - 2*bx, y - 2*by, z) - 5./22.*f(x - 3*bx, y - 3*by, z) + 1./22.*f(x - 4*bx, y - 4*by, z); } -void BoundaryNeumann_4thOrder::apply_ddt(Field2D &f) { - Field2D *dt = f.timeDeriv(); - for(bndry->first(); !bndry->isDone(); bndry->next()) - (*dt)(bndry->x,bndry->y) = 0.; // Set time derivative to zero +void BoundaryNeumann_4thOrder::applyAtPointStaggered(Field2D &UNUSED(f), BoutReal UNUSED(val), int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), Coordinates* UNUSED(metric)) { + throw BoutException("BoundaryNeumann_4thOrder is not implemented for staggered grids."); +} +void BoundaryNeumann_4thOrder::applyAtPointStaggered(Field3D &UNUSED(f), BoutReal UNUSED(val), int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), Coordinates* UNUSED(metric)) { + throw BoutException("BoundaryNeumann_4thOrder is not implemented for staggered grids."); } -void BoundaryNeumann_4thOrder::apply_ddt(Field3D &f) { - Field3D *dt = f.timeDeriv(); - for(bndry->first(); !bndry->isDone(); bndry->next()) - for(int z=0;zLocalNz;z++) - (*dt)(bndry->x,bndry->y,z) = 0.; // Set time derivative to zero +void BoundaryNeumann_4thOrder::extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) { + // Changing this extrapolation to not depend on val, so just using grid point + // values. Not sure if this is the correct order... Previously was + // f(x+bx,y+by,z) = -24.*delta*val + 27.*f(x,y,z) - 27.*f(x-bx,y-by,z) + f(x-2*bx,y-2*by,z); // The f(x-4*bx,y-4*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 + // - JTO 16/10/2018 + f(x, y, z) = 4.0*f(x - bx, y - by, z) - 6.0*f(x - 2*bx, y - 2*by, z) + + 4.0*f(x - 3*bx, y - 3*by, z) - f(x - 4*bx, y - 4*by, z); +} +void BoundaryNeumann_4thOrder::extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) { + // Changing this extrapolation to not depend on val, so just using grid point + // values. Not sure if this is the correct order... Previously was + // f(x+bx,y+by,z) = -24.*delta*val + 27.*f(x,y,z) - 27.*f(x-bx,y-by,z) + f(x-2*bx,y-2*by,z); // The f(x-4*bx,y-4*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 + // - JTO 16/10/2018 + f(x, y, z) = 4.0*f(x - bx, y - by, z) - 6.0*f(x - 2*bx, y - 2*by, z) + + 4.0*f(x - 3*bx, y - 3*by, z) - f(x - 4*bx, y - 4*by, z); } /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryNeumannPar::clone(BoundaryRegion *region, const list &args) { - verifyNumPoints(region,1); + verifyNumPoints(region, 1); + + std::shared_ptr newgen = nullptr; if(!args.empty()) { - output << "WARNING: Ignoring arguments to BoundaryNeumann2\n"; + output << "WARNING: Ignoring arguments to BoundaryNeumannPar\n"; } - return new BoundaryNeumannPar(region); + return new BoundaryNeumannPar(region, newgen); } - -void BoundaryNeumannPar::apply(Field2D &f) { - Coordinates *metric = f.getCoordinates(); - // Loop over all elements and set equal to the next point in - for(bndry->first(); !bndry->isDone(); bndry->next()) - f(bndry->x, bndry->y) = f(bndry->x - bndry->bx, bndry->y - bndry->by)*sqrt(metric->g_22(bndry->x, bndry->y)/metric->g_22(bndry->x - bndry->bx, bndry->y - bndry->by)); +void BoundaryNeumannPar::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* metric) { + // For each element, set equal to the next point in + f(x, y, z) = f(x - bx, y - by, z)*sqrt(metric->g_22(x, y)/metric->g_22(x - bx, y - by)); +} +void BoundaryNeumannPar::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* metric) { + // For each element, set equal to the next point in + f(x, y, z) = f(x - bx, y - by, z)*sqrt(metric->g_22(x, y)/metric->g_22(x - bx, y - by)); } -void BoundaryNeumannPar::apply(Field3D &f) { - Coordinates *metric = f.getCoordinates(); - for(bndry->first(); !bndry->isDone(); bndry->next()) - 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)); +void BoundaryNeumannPar::applyAtPointStaggered(Field2D &UNUSED(f), BoutReal UNUSED(val), int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), Coordinates* UNUSED(metric)) { + throw BoutException("BoundaryNeumannPar is not implemented for staggered grids."); +} +void BoundaryNeumannPar::applyAtPointStaggered(Field3D &UNUSED(f), BoutReal UNUSED(val), int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), Coordinates* UNUSED(metric)) { + throw BoutException("BoundaryNeumannPar is not implemented for staggered grids."); } /////////////////////////////////////////////////////////////// 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(); @@ -2343,70 +838,59 @@ BoundaryOp* BoundaryRobin::clone(BoundaryRegion *region, const list &arg return new BoundaryRobin(region, a, b, g); } -void BoundaryRobin::apply(Field2D &f) { - if(fabs(bval) < 1.e-12) { - // No derivative term so just constant value - for(bndry->first(); !bndry->isDone(); bndry->next()) - f(bndry->x, bndry->y) = gval / aval; - }else { - BoutReal sign = 1.; - if( (bndry->bx < 0) || (bndry->by < 0)) - sign = -1.; - for(bndry->first(); !bndry->isDone(); bndry->next()) - f(bndry->x, bndry->y) = f(bndry->x - bndry->bx,bndry->y - bndry->by) + sign*(gval - aval*f(bndry->x - bndry->bx,bndry->y - bndry->by) ) / bval; - } -} - -void BoundaryRobin::apply(Field3D &f) { +template +void BoundaryRobin::applyTemplate(T &f, BoutReal UNUSED(t)) { if(fabs(bval) < 1.e-12) { for(bndry->first(); !bndry->isDone(); bndry->next()) - for(int z=0;zLocalNz;z++) + for(int z=0; zx, 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; zx, 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; } } /////////////////////////////////////////////////////////////// -void BoundaryConstGradient::apply(Field2D &f){ - // Loop over all elements and set equal to the next point in - for(bndry->first(); !bndry->isDone(); bndry->next()) - f(bndry->x, bndry->y) = 2.*f(bndry->x - bndry->bx,bndry->y - bndry->by) - f(bndry->x - 2*bndry->bx,bndry->y - 2*bndry->by); -} - -void BoundaryConstGradient::apply(Field3D &f) { - for(bndry->first(); !bndry->isDone(); bndry->next()) - 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); + + std::shared_ptr newgen = nullptr; if(!args.empty()) { output << "WARNING: Ignoring arguments to BoundaryConstGradient\n"; } - return new BoundaryConstGradient(region); + return new BoundaryConstGradient(region, newgen); +} + +void BoundaryConstGradient::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = 2.*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z); +} +void BoundaryConstGradient::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = 2.*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z); +} + +void BoundaryConstGradient::applyAtPointStaggered(Field2D &UNUSED(f), BoutReal UNUSED(val), int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), Coordinates* UNUSED(metric)) { + throw BoutException("BoundaryConstGradient is not implemented for staggered grids."); +} +void BoundaryConstGradient::applyAtPointStaggered(Field3D &UNUSED(f), BoutReal UNUSED(val), int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), Coordinates* UNUSED(metric)) { + throw BoutException("BoundaryConstGradient is not implemented for staggered grids."); } /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryZeroLaplace::clone(BoundaryRegion *region, const list &args) { - verifyNumPoints(region,2); + verifyNumPoints(region, 2); if(!args.empty()) { output << "WARNING: Ignoring arguments to BoundaryZeroLaplace\n"; } return new BoundaryZeroLaplace(region); } -void BoundaryZeroLaplace::apply(Field2D &f) { +void BoundaryZeroLaplace::apply(Field2D &f, BoutReal UNUSED(t)) { Coordinates *metric = f.getCoordinates(); if((bndry->location != BNDRY_XIN) && (bndry->location != BNDRY_XOUT)) { // Can't apply this boundary condition to non-X boundaries @@ -2428,8 +912,10 @@ void BoundaryZeroLaplace::apply(Field2D &f) { } } -void BoundaryZeroLaplace::apply(Field3D &f) { - int ncz = mesh->LocalNz; +void BoundaryZeroLaplace::apply(Field3D &f, BoutReal UNUSED(t)) { + Mesh* localmesh = f.getMesh(); + + int ncz = localmesh->LocalNz; Coordinates *metric = f.getCoordinates(); @@ -2452,8 +938,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 +958,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; @@ -2492,7 +978,7 @@ BoundaryOp *BoundaryZeroLaplace2::clone(BoundaryRegion *region, return new BoundaryZeroLaplace2(region); } -void BoundaryZeroLaplace2::apply(Field2D &f) { +void BoundaryZeroLaplace2::apply(Field2D &f, BoutReal UNUSED(t)) { if ((bndry->location != BNDRY_XIN) && (bndry->location != BNDRY_XOUT)) { // Can't apply this boundary condition to non-X boundaries throw BoutException( @@ -2518,8 +1004,10 @@ void BoundaryZeroLaplace2::apply(Field2D &f) { } } -void BoundaryZeroLaplace2::apply(Field3D &f) { - int ncz = mesh->LocalNz; +void BoundaryZeroLaplace2::apply(Field3D &f, BoutReal UNUSED(t)) { + Mesh* localmesh = f.getMesh(); + + int ncz = localmesh->LocalNz; ASSERT0(ncz % 2 == 0); // Allocation assumes even number @@ -2572,14 +1060,14 @@ 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"; } return new BoundaryConstLaplace(region); } -void BoundaryConstLaplace::apply(Field2D &f) { +void BoundaryConstLaplace::apply(Field2D &f, BoutReal UNUSED(t)) { if((bndry->location != BNDRY_XIN) && (bndry->location != BNDRY_XOUT)) { // Can't apply this boundary condition to non-X boundaries throw BoutException("ERROR: Can't apply Zero Laplace condition to non-X boundaries\n"); @@ -2609,15 +1097,17 @@ void BoundaryConstLaplace::apply(Field2D &f) { } } -void BoundaryConstLaplace::apply(Field3D &f) { +void BoundaryConstLaplace::apply(Field3D &f, BoutReal UNUSED(t)) { if((bndry->location != BNDRY_XIN) && (bndry->location != BNDRY_XOUT)) { // Can't apply this boundary condition to non-X boundaries 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 +1176,23 @@ void BoundaryDivCurl::apply(Vector3D &var) { int jx, jy, jz, jzp, jzm; BoutReal tmp; - Coordinates *metric = mesh->getCoordinates(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 +1212,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 +1231,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); } @@ -2748,20 +1240,15 @@ void BoundaryDivCurl::apply(Vector3D &var) { /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryFree::clone(BoundaryRegion *region, const list &args) { - if(!args.empty()) { - // First argument should be a value - val = stringToReal(args.front()); - return new BoundaryFree(region, val); - } +BoundaryOp* BoundaryFree::clone(BoundaryRegion *region, const list &UNUSED(args)) { return new BoundaryFree(region); } -void BoundaryFree::apply(Field2D &UNUSED(f)) { +void BoundaryFree::apply(Field2D &UNUSED(f), BoutReal UNUSED(t)) { // Do nothing for free boundary } -void BoundaryFree::apply(Field3D &UNUSED(f)) { +void BoundaryFree::apply(Field3D &UNUSED(f), BoutReal UNUSED(t)) { // Do nothing for free boundary } @@ -2772,6 +1259,7 @@ void BoundaryFree::apply_ddt(Field2D &UNUSED(f)) { void BoundaryFree::apply_ddt(Field3D &UNUSED(f)) { // Do nothing for free boundary } + /////////////////////////////////////////////////////////////// // New free boundary implementation. Uses last grid points to extrapolate into the guard cells. // Written by L. Easy. @@ -2780,484 +1268,59 @@ 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"; + output << "WARNING: Ignoring arguments to BoundaryFree_O2\n"; } return new BoundaryFree_O2(region) ; } -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(); - - // 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); - } - } - } - 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); - } - - } - } - } - 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->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 - - 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); - } - } - } +void BoundaryFree_O2::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = 2*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z); } - -void BoundaryFree_O2::apply(Field3D &f) { - // Extrapolate from the last evolved simulation cells into the guard cells at 3rd order. - - bndry->first(); - - - // 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); - } - } - } - } - 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); - } - } - } - } - } - 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->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 - 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); - } - } - } - } +void BoundaryFree_O2::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = 2*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z); } -void BoundaryFree_O2::apply_ddt(Field2D &f) { - Field2D *dt = f.timeDeriv(); - for(bndry->first(); !bndry->isDone(); bndry->next()) - (*dt)(bndry->x,bndry->y) = 0.; // Set time derivative to zero +void BoundaryFree_O2::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = 2*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z); } - -void BoundaryFree_O2::apply_ddt(Field3D &f) { - Field3D *dt = f.timeDeriv(); - for(bndry->first(); !bndry->isDone(); bndry->next()) - for(int z=0;zLocalNz;z++) - (*dt)(bndry->x,bndry->y,z) = 0.; // Set time derivative to zero - +void BoundaryFree_O2::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = 2*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z); } ////////////////////////////////// // 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"; + output << "WARNING: Ignoring arguments to BoundaryFree_O3\n"; } return new BoundaryFree_O3(region) ; } -void BoundaryFree_O3::apply(Field2D &f) { - - bndry->first(); - - // 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); - } - } - } - 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); - } - - } - } - } - 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->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 - - 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); - } - } - } +void BoundaryFree_O3::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = 3.0*f(x - bx, y - by, z) - 3.0*f(x - 2*bx, y - 2*by, z) + f(x - 3*bx, y - 3*by, z); } - -void BoundaryFree_O3::apply(Field3D &f) { - // Extrapolate from the last evolved simulation cells into the guard cells at 3rd order. - - bndry->first(); - - - // 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); - } - } - } - } - 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); - } - } - } - } - } - 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->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 - 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); - } - } - } - } +void BoundaryFree_O3::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = 3.0*f(x - bx, y - by, z) - 3.0*f(x - 2*bx, y - 2*by, z) + f(x - 3*bx, y - 3*by, z); } -void BoundaryFree_O3::apply_ddt(Field2D &f) { - Field2D *dt = f.timeDeriv(); - for(bndry->first(); !bndry->isDone(); bndry->next()) - (*dt)(bndry->x,bndry->y) = 0.; // Set time derivative to zero +void BoundaryFree_O3::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = 3.0*f(x - bx, y - by, z) - 3.0*f(x - 2*bx, y - 2*by, z) + f(x - 3*bx, y - 3*by, z); +} +void BoundaryFree_O3::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = 3.0*f(x - bx, y - by, z) - 3.0*f(x - 2*bx, y - 2*by, z) + f(x - 3*bx, y - 3*by, z); } -void BoundaryFree_O3::apply_ddt(Field3D &f) { - Field3D *dt = f.timeDeriv(); - for(bndry->first(); !bndry->isDone(); bndry->next()) - for(int z=0;zLocalNz;z++) - (*dt)(bndry->x,bndry->y,z) = 0.; // Set time derivative to zero - +void BoundaryFree_O3::extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) { + f(x, y, z) = 3.0*f(x - bx, y - by, z) - 3.0*f(x - 2*bx, y - 2*by, z) + f(x - 3*bx, y - 3*by, z); +} +void BoundaryFree_O3::extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) { + f(x, y, z) = 3.0*f(x - bx, y - by, z) - 3.0*f(x - 2*bx, y - 2*by, z) + f(x - 3*bx, y - 3*by, z); } /////////////////////////////////////////////////////////////// @@ -3280,9 +1343,9 @@ void BoundaryRelax::apply(Field2D &f, BoutReal t) { op->apply(f, t); } -void BoundaryRelax::apply(Field3D &f, BoutReal UNUSED(t)) { +void BoundaryRelax::apply(Field3D &f, BoutReal t) { // Just apply the original boundary condition to f - op->apply(f); + op->apply(f, t); } void BoundaryRelax::apply_ddt(Field2D &f) { @@ -3304,13 +1367,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 +1442,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 +1463,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 +1489,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 +1510,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/makefile b/src/mesh/makefile index f5e19763a8..597d8afc53 100644 --- a/src/mesh/makefile +++ b/src/mesh/makefile @@ -3,11 +3,11 @@ BOUT_TOP = ../.. DIRS = impls parallel data interpolation -SOURCEC = difops.cxx interpolation.cxx mesh.cxx boundary_standard.cxx \ - boundary_factory.cxx boundary_region.cxx meshfactory.cxx \ - surfaceiter.cxx coordinates.cxx index_derivs.cxx \ - parallel_boundary_region.cxx parallel_boundary_op.cxx fv_ops.cxx -SOURCEH = $(SOURCEC:%.cxx=%.hxx) -TARGET = lib +SOURCEC = difops.cxx interpolation.cxx mesh.cxx boundary_op.cxx \ + boundary_standard.cxx boundary_factory.cxx boundary_region.cxx \ + meshfactory.cxx surfaceiter.cxx coordinates.cxx index_derivs.cxx \ + parallel_boundary_region.cxx parallel_boundary_op.cxx fv_ops.cxx +SOURCEH = $(SOURCEC:%.cxx=%.hxx) +TARGET = lib include $(BOUT_TOP)/make.config From 5fe8d3a668b682ea1ccf263956fa67b0a9389732 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 19 Oct 2018 14:28:12 +0100 Subject: [PATCH 11/45] Add 4th and 5th order extrapolation boundary conditions called "free_o4" and "free_o5". --- include/boundary_standard.hxx | 25 +++++++++++ src/mesh/boundary_factory.cxx | 2 + src/mesh/boundary_standard.cxx | 80 ++++++++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+) diff --git a/include/boundary_standard.hxx b/include/boundary_standard.hxx index 6a7769057f..ef9929d6e7 100644 --- a/include/boundary_standard.hxx +++ b/include/boundary_standard.hxx @@ -312,6 +312,31 @@ public: }; // End L.Easy +class BoundaryFree_O4 : public BoundaryOp { +public: + using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors + BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + + void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; + void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; + void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + void extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) override; + void extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) override; +}; + +class BoundaryFree_O5 : public BoundaryOp { +public: + using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors + BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + + void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; + void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; + void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + void extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) override; + void extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) override; +}; ///////////////////////////////////////////////////////// diff --git a/src/mesh/boundary_factory.cxx b/src/mesh/boundary_factory.cxx index 2ddf87c23a..86c4ff85aa 100644 --- a/src/mesh/boundary_factory.cxx +++ b/src/mesh/boundary_factory.cxx @@ -35,6 +35,8 @@ BoundaryFactory::BoundaryFactory() { add(new BoundaryFree(), "free"); add(new BoundaryFree_O2(), "free_o2"); add(new BoundaryFree_O3(), "free_o3"); + add(new BoundaryFree_O4(), "free_o4"); + add(new BoundaryFree_O5(), "free_o5"); addMod(new BoundaryRelax(), "relax"); addMod(new BoundaryWidth(), "width"); diff --git a/src/mesh/boundary_standard.cxx b/src/mesh/boundary_standard.cxx index c6209b64b6..2e9333edf4 100644 --- a/src/mesh/boundary_standard.cxx +++ b/src/mesh/boundary_standard.cxx @@ -1323,6 +1323,86 @@ void BoundaryFree_O3::extrapFurther(Field3D &f, int x, int bx, int y, int by, in f(x, y, z) = 3.0*f(x - bx, y - by, z) - 3.0*f(x - 2*bx, y - 2*by, z) + f(x - 3*bx, y - 3*by, z); } +// Fourth order extrapolation: +BoundaryOp* BoundaryFree_O4::clone(BoundaryRegion *region, const list &args){ + verifyNumPoints(region, 4); + + if(!args.empty()) { + output << "WARNING: Ignoring arguments to BoundaryFree_O4\n"; + } + return new BoundaryFree_O4(region); +} + +void BoundaryFree_O4::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = 4.0*f(x - bx, y - by, z) - 6.0*f(x - 2*bx, y - 2*by, z) + + 4.0*f(x - 3*bx, y - 3*by, z) - f(x - 4*bx, y - 4*by, z); +} +void BoundaryFree_O4::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = 4.0*f(x - bx, y - by, z) - 6.0*f(x - 2*bx, y - 2*by, z) + + 4.0*f(x - 3*bx, y - 3*by, z) - f(x - 4*bx, y - 4*by, z); +} + +void BoundaryFree_O4::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = 4.0*f(x - bx, y - by, z) - 6.0*f(x - 2*bx, y - 2*by, z) + + 4.0*f(x - 3*bx, y - 3*by, z) - f(x - 4*bx, y - 4*by, z); +} +void BoundaryFree_O4::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = 4.0*f(x - bx, y - by, z) - 6.0*f(x - 2*bx, y - 2*by, z) + + 4.0*f(x - 3*bx, y - 3*by, z) - f(x - 4*bx, y - 4*by, z); +} + +void BoundaryFree_O4::extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) { + f(x, y, z) = 4.0*f(x - bx, y - by, z) - 6.0*f(x - 2*bx, y - 2*by, z) + + 4.0*f(x - 3*bx, y - 3*by, z) - f(x - 4*bx, y - 4*by, z); +} +void BoundaryFree_O4::extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) { + f(x, y, z) = 4.0*f(x - bx, y - by, z) - 6.0*f(x - 2*bx, y - 2*by, z) + + 4.0*f(x - 3*bx, y - 3*by, z) - f(x - 4*bx, y - 4*by, z); +} + +// Fifth order extrapolation: +BoundaryOp* BoundaryFree_O5::clone(BoundaryRegion *region, const list &args){ + verifyNumPoints(region, 5); + + if(!args.empty()) { + output << "WARNING: Ignoring arguments to BoundaryFree_O5\n"; + } + return new BoundaryFree_O5(region); +} + +void BoundaryFree_O5::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = 5.0*f(x - bx, y - by, z) - 10.0*f(x - 2*bx, y - 2*by, z) + + 10.0*f(x - 3*bx, y - 3*by, z) - 5.0*f(x - 4*bx, y - 4*by, z) + + f(x - 5*bx, y - 5*by, z); +} +void BoundaryFree_O5::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = 5.0*f(x - bx, y - by, z) - 10.0*f(x - 2*bx, y - 2*by, z) + + 10.0*f(x - 3*bx, y - 3*by, z) - 5.0*f(x - 4*bx, y - 4*by, z) + + f(x - 5*bx, y - 5*by, z); +} + +void BoundaryFree_O5::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = 5.0*f(x - bx, y - by, z) - 10.0*f(x - 2*bx, y - 2*by, z) + + 10.0*f(x - 3*bx, y - 3*by, z) - 5.0*f(x - 4*bx, y - 4*by, z) + + f(x - 5*bx, y - 5*by, z); +} +void BoundaryFree_O5::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = 5.0*f(x - bx, y - by, z) - 10.0*f(x - 2*bx, y - 2*by, z) + + 10.0*f(x - 3*bx, y - 3*by, z) - 5.0*f(x - 4*bx, y - 4*by, z) + + f(x - 5*bx, y - 5*by, z); +} + +void BoundaryFree_O5::extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) { + f(x, y, z) = 5.0*f(x - bx, y - by, z) - 10.0*f(x - 2*bx, y - 2*by, z) + + 10.0*f(x - 3*bx, y - 3*by, z) - 5.0*f(x - 4*bx, y - 4*by, z) + + f(x - 5*bx, y - 5*by, z); +} +void BoundaryFree_O5::extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) { + f(x, y, z) = 5.0*f(x - bx, y - by, z) - 10.0*f(x - 2*bx, y - 2*by, z) + + 10.0*f(x - 3*bx, y - 3*by, z) - 5.0*f(x - 4*bx, y - 4*by, z) + + f(x - 5*bx, y - 5*by, z); +} + /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryRelax::cloneMod(BoundaryOp *operation, const list &args) { From 20b69739e7111eab1f6beff4575da3f4583ed5ae Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 21 Oct 2018 18:25:11 +0100 Subject: [PATCH 12/45] Utility funcs for 2nd-5th order extrapolation in boundary_standard.cxx --- src/mesh/boundary_standard.cxx | 127 ++++++++++++++++----------------- 1 file changed, 62 insertions(+), 65 deletions(-) diff --git a/src/mesh/boundary_standard.cxx b/src/mesh/boundary_standard.cxx index 2e9333edf4..f1fa3b6f9a 100644 --- a/src/mesh/boundary_standard.cxx +++ b/src/mesh/boundary_standard.cxx @@ -101,6 +101,33 @@ namespace { #endif } + + // 2nd order extrapolation to a point + template + void extrap2nd(T &f, int x, int bx, int y, int by, int z) { + f(x, y, z) = 2*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z); + } + + // 3rd order extrapolation to a point + template + void extrap3rd(T &f, int x, int bx, int y, int by, int z) { + f(x, y, z) = 3.0*f(x - bx, y - by, z) - 3.0*f(x - 2*bx, y - 2*by, z) + f(x - 3*bx, y - 3*by, z); + } + + // 4th order extrapolation to a point + template + void extrap4th(T &f, int x, int bx, int y, int by, int z) { + f(x, y, z) = 4.0*f(x - bx, y - by, z) - 6.0*f(x - 2*bx, y - 2*by, z) + + 4.0*f(x - 3*bx, y - 3*by, z) - f(x - 4*bx, y - 4*by, z); + } + + // 5th order extrapolation to a point + template + void extrap5th(T &f, int x, int bx, int y, int by, int z) { + f(x, y, z) = 5.0*f(x - bx, y - by, z) - 10.0*f(x - 2*bx, y - 2*by, z) + + 10.0*f(x - 3*bx, y - 3*by, z) - 5.0*f(x - 4*bx, y - 4*by, z) + + f(x - 5*bx, y - 5*by, z); + } } /////////////////////////////////////////////////////////////// @@ -411,10 +438,10 @@ void BoundaryDirichlet_O3::applyAtPointStaggered(Field3D &f, BoutReal val, int x } void BoundaryDirichlet_O3::extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) { - f(x, y, z) = 3.0*f(x - bx, y - by, z) - 3.0*f(x - 2*bx, y - 2*by, z) + f(x - 3*bx, y - 3*by, z); + extrap3rd(f, x, bx, y, by, z); } void BoundaryDirichlet_O3::extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) { - f(x, y, z) = 3.0*f(x - bx, y - by, z) - 3.0*f(x - 2*bx, y - 2*by, z) + f(x - 3*bx, y - 3*by, z); + extrap3rd(f, x, bx, y, by, z); } /////////////////////////////////////////////////////////////// @@ -446,12 +473,10 @@ void BoundaryDirichlet_O4::applyAtPointStaggered(Field3D &f, BoutReal val, int x } void BoundaryDirichlet_O4::extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) { - f(x, y, z) = 4.0*f(x - bx, y - by, z) - 6.0*f(x - 2*bx, y - 2*by, z) - + 4.0*f(x - 3*bx, y - 3*by, z) - f(x - 4*bx, y - 4*by, z); + extrap4th(f, x, bx, y, by, z); } void BoundaryDirichlet_O4::extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) { - f(x, y, z) = 4.0*f(x - bx, y - by, z) - 6.0*f(x - 2*bx, y - 2*by, z) - + 4.0*f(x - 3*bx, y - 3*by, z) - f(x - 4*bx, y - 4*by, z); + extrap4th(f, x, bx, y, by, z); } /////////////////////////////////////////////////////////////// @@ -514,17 +539,13 @@ void BoundaryDirichlet_4thOrder::applyAtPointStaggered(Field3D &f, BoutReal val, void BoundaryDirichlet_4thOrder::extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) { // Changing this extrapolation to not depend on val, so just using grid point - // values. Not sure if this is the correct order... JTO 16/10/2018 - f(x, y, z) = 5.0*f(x - bx, y - by, z) - 10.0*f(x - 2*bx, y - 2*by, z) - + 10.0*f(x - 3*bx, y - 3*by, z) - 5.0*f(x - 4*bx, y - 4*by, z) - + f(x - 5*bx, y - 5*by, z); + // values. JTO 16/10/2018 + extrap5th(f, x, bx, y, by, z); } void BoundaryDirichlet_4thOrder::extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) { // Changing this extrapolation to not depend on val, so just using grid point // values. Not sure if this is the correct order... JTO 16/10/2018 - f(x, y, z) = 5.0*f(x - bx, y - by, z) - 10.0*f(x - 2*bx, y - 2*by, z) - + 10.0*f(x - 3*bx, y - 3*by, z) - 5.0*f(x - 4*bx, y - 4*by, z) - + f(x - 5*bx, y - 5*by, z); + extrap5th(f, x, bx, y, by, z); } @@ -722,14 +743,10 @@ void BoundaryNeumann_O4::applyAtPointStaggered(Field3D &f, BoutReal val, int x, } void BoundaryNeumann_O4::extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) { - f(x, y, z) = 5.0*f(x - bx, y - by, z) - 10.0*f(x - 2*bx, y - 2*by, z) - + 10.0*f(x - 3*bx, y - 3*by, z) - 5.0*f(x - 4*bx, y - 4*by, z) - + f(x - 5*bx, y - 5*by, z); + extrap5th(f, x, bx, y, by, z); } void BoundaryNeumann_O4::extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) { - f(x, y, z) = 5.0*f(x - bx, y - by, z) - 10.0*f(x - 2*bx, y - 2*by, z) - + 10.0*f(x - 3*bx, y - 3*by, z) - 5.0*f(x - 4*bx, y - 4*by, z) - + f(x - 5*bx, y - 5*by, z); + extrap5th(f, x, bx, y, by, z); } /////////////////////////////////////////////////////////////// @@ -763,19 +780,17 @@ void BoundaryNeumann_4thOrder::applyAtPointStaggered(Field3D &UNUSED(f), BoutRea void BoundaryNeumann_4thOrder::extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) { // Changing this extrapolation to not depend on val, so just using grid point - // values. Not sure if this is the correct order... Previously was + // values. Previously was: // f(x+bx,y+by,z) = -24.*delta*val + 27.*f(x,y,z) - 27.*f(x-bx,y-by,z) + f(x-2*bx,y-2*by,z); // The f(x-4*bx,y-4*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 // - JTO 16/10/2018 - f(x, y, z) = 4.0*f(x - bx, y - by, z) - 6.0*f(x - 2*bx, y - 2*by, z) - + 4.0*f(x - 3*bx, y - 3*by, z) - f(x - 4*bx, y - 4*by, z); + extrap5th(f, x, bx, y, by, z); } void BoundaryNeumann_4thOrder::extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) { // Changing this extrapolation to not depend on val, so just using grid point - // values. Not sure if this is the correct order... Previously was + // values. Previously was // f(x+bx,y+by,z) = -24.*delta*val + 27.*f(x,y,z) - 27.*f(x-bx,y-by,z) + f(x-2*bx,y-2*by,z); // The f(x-4*bx,y-4*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 // - JTO 16/10/2018 - f(x, y, z) = 4.0*f(x - bx, y - by, z) - 6.0*f(x - 2*bx, y - 2*by, z) - + 4.0*f(x - 3*bx, y - 3*by, z) - f(x - 4*bx, y - 4*by, z); + extrap5th(f, x, bx, y, by, z); } /////////////////////////////////////////////////////////////// @@ -1277,17 +1292,17 @@ BoundaryOp* BoundaryFree_O2::clone(BoundaryRegion *region, const list &a } void BoundaryFree_O2::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { - f(x, y, z) = 2*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z); + extrap2nd(f, x, bx, y, by, z); } void BoundaryFree_O2::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { - f(x, y, z) = 2*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z); + extrap2nd(f, x, bx, y, by, z); } void BoundaryFree_O2::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { - f(x, y, z) = 2*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z); + extrap2nd(f, x, bx, y, by, z); } void BoundaryFree_O2::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { - f(x, y, z) = 2*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z); + extrap2nd(f, x, bx, y, by, z); } ////////////////////////////////// @@ -1303,24 +1318,24 @@ BoundaryOp* BoundaryFree_O3::clone(BoundaryRegion *region, const list &a } void BoundaryFree_O3::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { - f(x, y, z) = 3.0*f(x - bx, y - by, z) - 3.0*f(x - 2*bx, y - 2*by, z) + f(x - 3*bx, y - 3*by, z); + extrap3rd(f, x, bx, y, by, z); } void BoundaryFree_O3::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { - f(x, y, z) = 3.0*f(x - bx, y - by, z) - 3.0*f(x - 2*bx, y - 2*by, z) + f(x - 3*bx, y - 3*by, z); + extrap3rd(f, x, bx, y, by, z); } void BoundaryFree_O3::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { - f(x, y, z) = 3.0*f(x - bx, y - by, z) - 3.0*f(x - 2*bx, y - 2*by, z) + f(x - 3*bx, y - 3*by, z); + extrap3rd(f, x, bx, y, by, z); } void BoundaryFree_O3::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { - f(x, y, z) = 3.0*f(x - bx, y - by, z) - 3.0*f(x - 2*bx, y - 2*by, z) + f(x - 3*bx, y - 3*by, z); + extrap3rd(f, x, bx, y, by, z); } void BoundaryFree_O3::extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) { - f(x, y, z) = 3.0*f(x - bx, y - by, z) - 3.0*f(x - 2*bx, y - 2*by, z) + f(x - 3*bx, y - 3*by, z); + extrap3rd(f, x, bx, y, by, z); } void BoundaryFree_O3::extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) { - f(x, y, z) = 3.0*f(x - bx, y - by, z) - 3.0*f(x - 2*bx, y - 2*by, z) + f(x - 3*bx, y - 3*by, z); + extrap3rd(f, x, bx, y, by, z); } // Fourth order extrapolation: @@ -1334,30 +1349,24 @@ BoundaryOp* BoundaryFree_O4::clone(BoundaryRegion *region, const list &a } void BoundaryFree_O4::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { - f(x, y, z) = 4.0*f(x - bx, y - by, z) - 6.0*f(x - 2*bx, y - 2*by, z) - + 4.0*f(x - 3*bx, y - 3*by, z) - f(x - 4*bx, y - 4*by, z); + extrap4th(f, x, bx, y, by, z); } void BoundaryFree_O4::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { - f(x, y, z) = 4.0*f(x - bx, y - by, z) - 6.0*f(x - 2*bx, y - 2*by, z) - + 4.0*f(x - 3*bx, y - 3*by, z) - f(x - 4*bx, y - 4*by, z); + extrap4th(f, x, bx, y, by, z); } void BoundaryFree_O4::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { - f(x, y, z) = 4.0*f(x - bx, y - by, z) - 6.0*f(x - 2*bx, y - 2*by, z) - + 4.0*f(x - 3*bx, y - 3*by, z) - f(x - 4*bx, y - 4*by, z); + extrap4th(f, x, bx, y, by, z); } void BoundaryFree_O4::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { - f(x, y, z) = 4.0*f(x - bx, y - by, z) - 6.0*f(x - 2*bx, y - 2*by, z) - + 4.0*f(x - 3*bx, y - 3*by, z) - f(x - 4*bx, y - 4*by, z); + extrap4th(f, x, bx, y, by, z); } void BoundaryFree_O4::extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) { - f(x, y, z) = 4.0*f(x - bx, y - by, z) - 6.0*f(x - 2*bx, y - 2*by, z) - + 4.0*f(x - 3*bx, y - 3*by, z) - f(x - 4*bx, y - 4*by, z); + extrap4th(f, x, bx, y, by, z); } void BoundaryFree_O4::extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) { - f(x, y, z) = 4.0*f(x - bx, y - by, z) - 6.0*f(x - 2*bx, y - 2*by, z) - + 4.0*f(x - 3*bx, y - 3*by, z) - f(x - 4*bx, y - 4*by, z); + extrap4th(f, x, bx, y, by, z); } // Fifth order extrapolation: @@ -1371,36 +1380,24 @@ BoundaryOp* BoundaryFree_O5::clone(BoundaryRegion *region, const list &a } void BoundaryFree_O5::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { - f(x, y, z) = 5.0*f(x - bx, y - by, z) - 10.0*f(x - 2*bx, y - 2*by, z) - + 10.0*f(x - 3*bx, y - 3*by, z) - 5.0*f(x - 4*bx, y - 4*by, z) - + f(x - 5*bx, y - 5*by, z); + extrap5th(f, x, bx, y, by, z); } void BoundaryFree_O5::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { - f(x, y, z) = 5.0*f(x - bx, y - by, z) - 10.0*f(x - 2*bx, y - 2*by, z) - + 10.0*f(x - 3*bx, y - 3*by, z) - 5.0*f(x - 4*bx, y - 4*by, z) - + f(x - 5*bx, y - 5*by, z); + extrap5th(f, x, bx, y, by, z); } void BoundaryFree_O5::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { - f(x, y, z) = 5.0*f(x - bx, y - by, z) - 10.0*f(x - 2*bx, y - 2*by, z) - + 10.0*f(x - 3*bx, y - 3*by, z) - 5.0*f(x - 4*bx, y - 4*by, z) - + f(x - 5*bx, y - 5*by, z); + extrap5th(f, x, bx, y, by, z); } void BoundaryFree_O5::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { - f(x, y, z) = 5.0*f(x - bx, y - by, z) - 10.0*f(x - 2*bx, y - 2*by, z) - + 10.0*f(x - 3*bx, y - 3*by, z) - 5.0*f(x - 4*bx, y - 4*by, z) - + f(x - 5*bx, y - 5*by, z); + extrap5th(f, x, bx, y, by, z); } void BoundaryFree_O5::extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) { - f(x, y, z) = 5.0*f(x - bx, y - by, z) - 10.0*f(x - 2*bx, y - 2*by, z) - + 10.0*f(x - 3*bx, y - 3*by, z) - 5.0*f(x - 4*bx, y - 4*by, z) - + f(x - 5*bx, y - 5*by, z); + extrap5th(f, x, bx, y, by, z); } void BoundaryFree_O5::extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) { - f(x, y, z) = 5.0*f(x - bx, y - by, z) - 10.0*f(x - 2*bx, y - 2*by, z) - + 10.0*f(x - 3*bx, y - 3*by, z) - 5.0*f(x - 4*bx, y - 4*by, z) - + f(x - 5*bx, y - 5*by, z); + extrap5th(f, x, bx, y, by, z); } /////////////////////////////////////////////////////////////// From d40cd41254349f442be4ae376ec41347623eef9e Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 19 Oct 2018 14:32:03 +0100 Subject: [PATCH 13/45] Rename BoundaryDirichlet_4thOrder to BoundaryDirichlet_O5 Makes it consistent with standard naming scheme. Can be called with either option "dirichlet_o5" or (now deprecated) "dirichlet_4thorder". --- include/boundary_standard.hxx | 2 +- src/mesh/boundary_factory.cxx | 3 ++- src/mesh/boundary_standard.cxx | 16 ++++++++-------- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/include/boundary_standard.hxx b/include/boundary_standard.hxx index ef9929d6e7..1961d81e30 100644 --- a/include/boundary_standard.hxx +++ b/include/boundary_standard.hxx @@ -72,7 +72,7 @@ class BoundaryDirichlet_2ndOrder : public BoundaryOp { }; /// Dirichlet boundary condition set half way between guard cell and grid cell at 4th order accuracy -class BoundaryDirichlet_4thOrder : public BoundaryOp { +class BoundaryDirichlet_O5 : public BoundaryOp { public: using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors BoundaryOp* clone(BoundaryRegion *region, const list &args) override; diff --git a/src/mesh/boundary_factory.cxx b/src/mesh/boundary_factory.cxx index 86c4ff85aa..3ac89764f4 100644 --- a/src/mesh/boundary_factory.cxx +++ b/src/mesh/boundary_factory.cxx @@ -18,7 +18,8 @@ BoundaryFactory::BoundaryFactory() { add(new BoundaryDirichlet_2ndOrder(), "dirichlet_2ndorder"); // Deprecated add(new BoundaryDirichlet_O3(), "dirichlet_o3"); add(new BoundaryDirichlet_O4(), "dirichlet_o4"); - add(new BoundaryDirichlet_4thOrder(), "dirichlet_4thorder"); + add(new BoundaryDirichlet_O5(), "dirichlet_o5"); + add(new BoundaryDirichlet_O5(), "dirichlet_4thorder"); // Synonym for "dirichlet_o5" add(new BoundaryNeumann(), "neumann"); add(new BoundaryNeumann(), "neumann_O2"); // Synonym for "neumann" add(new BoundaryNeumann2(), "neumann2"); // Deprecated diff --git a/src/mesh/boundary_standard.cxx b/src/mesh/boundary_standard.cxx index f1fa3b6f9a..3f7fa31853 100644 --- a/src/mesh/boundary_standard.cxx +++ b/src/mesh/boundary_standard.cxx @@ -512,7 +512,7 @@ void BoundaryDirichlet_2ndOrder::applyAtPointStaggered(Field3D &f, BoutReal val, /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryDirichlet_4thOrder::clone(BoundaryRegion *region, const list &args) { +BoundaryOp* BoundaryDirichlet_O5::clone(BoundaryRegion *region, const list &args) { verifyNumPoints(region, 4); std::shared_ptr newgen = nullptr; @@ -520,29 +520,29 @@ BoundaryOp* BoundaryDirichlet_4thOrder::clone(BoundaryRegion *region, const list // First argument should be an expression newgen = FieldFactory::get()->parse(args.front()); } - return new BoundaryDirichlet_4thOrder(region, newgen); + return new BoundaryDirichlet_O5(region, newgen); } -void BoundaryDirichlet_4thOrder::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { +void BoundaryDirichlet_O5::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { f(x, y, z) = 128./35.*val - 4.*f(x - bx, y - by, z) + 2.*f(x - 2*bx, y - 2*by, z) - 4./5.*f(x - 3*bx, y - 3*by, z) + 1./7.*f(x - 4*bx, y - 4*by, z); } -void BoundaryDirichlet_4thOrder::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { +void BoundaryDirichlet_O5::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { f(x, y, z) = 128./35.*val - 4.*f(x - bx, y - by, z) + 2.*f(x - 2*bx, y - 2*by, z) - 4./5.*f(x - 3*bx, y - 3*by, z) + 1./7.*f(x - 4*bx, y - 4*by, z); } -void BoundaryDirichlet_4thOrder::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) { +void BoundaryDirichlet_O5::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) { f(x, y, z) = val; } -void BoundaryDirichlet_4thOrder::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) { +void BoundaryDirichlet_O5::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) { f(x, y, z) = val; } -void BoundaryDirichlet_4thOrder::extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) { +void BoundaryDirichlet_O5::extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) { // Changing this extrapolation to not depend on val, so just using grid point // values. JTO 16/10/2018 extrap5th(f, x, bx, y, by, z); } -void BoundaryDirichlet_4thOrder::extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) { +void BoundaryDirichlet_O5::extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) { // Changing this extrapolation to not depend on val, so just using grid point // values. Not sure if this is the correct order... JTO 16/10/2018 extrap5th(f, x, bx, y, by, z); From a0c85deac838fd72c1811e9a28aeba54cedb033b Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 19 Oct 2018 15:57:31 +0100 Subject: [PATCH 14/45] Make 'Robin' boundary condition inputs independent of grid spacing Previously BoundaryRobin::apply did not take account of the grid spacing dx/dy for the derivative term, so dx/dy would have to be included in its input. --- src/mesh/boundary_standard.cxx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/mesh/boundary_standard.cxx b/src/mesh/boundary_standard.cxx index 3f7fa31853..af838095fb 100644 --- a/src/mesh/boundary_standard.cxx +++ b/src/mesh/boundary_standard.cxx @@ -860,12 +860,13 @@ void BoundaryRobin::applyTemplate(T &f, BoutReal UNUSED(t)) { for(int z=0; zx, 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; zx, 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; + Coordinates* metric = f.getCoordinates(); + for(bndry->first(); !bndry->isDone(); bndry->next()) { + BoutReal delta = bndry->bx*metric->dx(bndry->x, bndry->y) + bndry->by*metric->dy(bndry->x, bndry->y); + for(int z=0; zx, bndry->y, z) = f(bndry->x - bndry->bx, bndry->y - bndry->by, z) + (gval - aval*f(bndry->x - bndry->bx, bndry->y - bndry->by, z) ) * delta / bval; + } + } } } From 5e23d20b23acd6cbe0c26da0890099ee2ef76475 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 18 Oct 2018 16:14:34 +0100 Subject: [PATCH 15/45] Add optional region argument to boutcore.Field*D.applyBoundary() --- tools/pylib/_boutcore_build/boutcore.pyx.in | 16 +++++++++++++--- tools/pylib/_boutcore_build/boutcpp.pxd.in | 1 + 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/tools/pylib/_boutcore_build/boutcore.pyx.in b/tools/pylib/_boutcore_build/boutcore.pyx.in index 63559f9786..2d69d4c666 100755 --- a/tools/pylib/_boutcore_build/boutcore.pyx.in +++ b/tools/pylib/_boutcore_build/boutcore.pyx.in @@ -572,7 +572,7 @@ EOF done cat < Date: Thu, 18 Oct 2018 17:50:33 +0100 Subject: [PATCH 16/45] Test boundary conditions in MMS/derivatives3 Apply x- and y-boundary conditions in MMS/derivatives3 to test their accuracy and correctness. Tests Dirichlet, Neumann and Free boundary conditions. --- tests/MMS/derivatives3/data/BOUT.inp | 3 +- tests/MMS/derivatives3/runtest | 169 +++++++++++++++++++++++---- 2 files changed, 148 insertions(+), 24 deletions(-) diff --git a/tests/MMS/derivatives3/data/BOUT.inp b/tests/MMS/derivatives3/data/BOUT.inp index 13db66011d..c346c7626f 100644 --- a/tests/MMS/derivatives3/data/BOUT.inp +++ b/tests/MMS/derivatives3/data/BOUT.inp @@ -35,7 +35,8 @@ n=6 dy=2*Pi/ny MXG=0 MYG=2 - +ixseps1 = -1 +ixseps2 = -1 [meshx] staggergrids=true diff --git a/tests/MMS/derivatives3/runtest b/tests/MMS/derivatives3/runtest index c3f64624cb..2d5176b792 100755 --- a/tests/MMS/derivatives3/runtest +++ b/tests/MMS/derivatives3/runtest @@ -16,25 +16,135 @@ boutcore.init("-d data -q -q -q".split(" ")) def runtests(functions,derivatives,directions,stag,msg): global errorlist for direction in directions: - direction, fac,guards, diff_func = direction + direction, fac,guards, diff_func, diff_order = direction locations=['CENTRE'] if stag: locations.append(direction.upper()+"LOW") - for funcs, derivative , inloc, outloc in itertools.product(functions, - derivatives, locations,locations): - infunc, outfunc = funcs + for funcs, derivative , inloc, outloc, testBoundaries \ + in itertools.product(functions, derivatives, locations, locations, [0,1,2]): + infunc, outfunc, difffunc = funcs order, diff = derivative + expected_order = order errors=[] + errors_L2=[] for nz in nzs: + dirnfac=direction+"*"+fac + this_infunc = infunc.replace("%s",dirnfac) + this_outfunc = outfunc.replace("%s",dirnfac) + this_difffunc = difffunc.replace("%s",dirnfac) boutcore.setOption("meshD:nD".replace("D",direction) ,"%d"% (nz+ (2*guards if direction == "x" else 0)),force=True) boutcore.setOption("meshD:dD".replace("D",direction,) ,"2*pi/(%d)"%(nz),force=True) - dirnfac=direction+"*"+fac mesh=boutcore.Mesh(section="mesh"+direction) - f=boutcore.create3D(infunc.replace("%s",dirnfac),mesh + f=boutcore.create3D(this_infunc,mesh ,outloc=inloc) + if testBoundaries == 0: + # test derivative operators without relying on boundary conditions + pass + if testBoundaries == 1: + if diff_order == 1: + if order==2: + if direction == "x": + f.applyBoundary(boundary="dirichlet_o3(%s)"%(this_infunc), region="core") + f.applyBoundary(boundary="neumann_o2(%s)"%(this_difffunc), region="sol") + if direction == "y": + f.applyBoundary(boundary="neumann_o2(%s)"%(this_difffunc), region="lower_target") + f.applyBoundary(boundary="dirichlet_o3(%s)"%(this_infunc), region="upper_target") + elif order==3: + if direction == "x": + f.applyBoundary(boundary="dirichlet_o4(%s)"%(this_infunc), region="core") + f.applyBoundary(boundary="neumann_o4(%s)"%(this_difffunc), region="sol") + if direction == "y": + f.applyBoundary(boundary="neumann_o4(%s)"%(this_difffunc), region="lower_target") + f.applyBoundary(boundary="dirichlet_o4(%s)"%(this_infunc), region="upper_target") + elif order==4: + if direction == "x": + f.applyBoundary(boundary="dirichlet_o5(%s)"%(this_infunc), region="core") + f.applyBoundary(boundary="neumann_o4(%s)"%(this_difffunc), region="sol") + if direction == "y": + f.applyBoundary(boundary="neumann_o4(%s)"%(this_difffunc), region="lower_target") + f.applyBoundary(boundary="dirichlet_o5(%s)"%(this_infunc), region="upper_target") + elif diff_order == 2: + if order==2: + if direction == "x": + f.applyBoundary(boundary="dirichlet_o4(%s)"%(this_infunc), region="core") + f.applyBoundary(boundary="neumann_o4(%s)"%(this_difffunc), region="sol") # there is no neumann_o3 + if direction == "y": + f.applyBoundary(boundary="neumann_o4(%s)"%(this_difffunc), region="lower_target") # there is no neumann_o3 + f.applyBoundary(boundary="dirichlet_o4(%s)"%(this_infunc), region="upper_target") + elif order==3: + if direction == "x": + f.applyBoundary(boundary="dirichlet_o5(%s)"%(this_infunc), region="core") + f.applyBoundary(boundary="neumann_o4(%s)"%(this_difffunc), region="sol") + if direction == "y": + f.applyBoundary(boundary="neumann_o4(%s)"%(this_difffunc), region="lower_target") + f.applyBoundary(boundary="dirichlet_o5(%s)"%(this_infunc), region="upper_target") + elif order==4: + if direction == "x": + f.applyBoundary(boundary="dirichlet_o5(%s)"%(this_infunc), region="core") + f.applyBoundary(boundary="neumann_o4(%s)"%(this_difffunc), region="sol") + if direction == "y": + f.applyBoundary(boundary="dirichlet_o5(%s)"%(this_infunc), region="upper_target") + f.applyBoundary(boundary="neumann_o4(%s)"%(this_difffunc), region="lower_target") + # don't have accurate enough boundary conditions, so reduce expected order + expected_order = 3 + else: + raise ValueError("don't know how to test a derivatives higher than d2/d*2") + if testBoundaries == 2: + if diff_order == 1: + if order==2: + if direction == "x": + f.applyBoundary(boundary="dirichlet(%s)"%(this_infunc), region="core") + f.applyBoundary(boundary="free_o2", region="sol") + expected_order = 1 # reduce expected order because free_o2 is not accurate enough for order=2 + if direction == "y": + f.applyBoundary(boundary="free_o3", region="lower_target") + f.applyBoundary(boundary="free_o3", region="upper_target") + elif order==3: + if direction == "x": + f.applyBoundary(boundary="free_o4", region="core") + f.applyBoundary(boundary="free_o4", region="sol") + if direction == "y": + f.applyBoundary(boundary="free_o4", region="lower_target") + f.applyBoundary(boundary="free_o4", region="upper_target") + elif order==4: + if direction == "x": + f.applyBoundary(boundary="free_o4", region="core") + f.applyBoundary(boundary="free_o4", region="sol") + expected_order = 3 + if direction == "y": + f.applyBoundary(boundary="free_o5", region="lower_target") + f.applyBoundary(boundary="free_o5", region="upper_target") + elif diff_order == 2: + if order==2: + if direction == "x": + f.applyBoundary(boundary="free_o4", region="core") + f.applyBoundary(boundary="free_o4", region="sol") # there is no neumann_o3 + if direction == "y": + f.applyBoundary(boundary="free_o4", region="lower_target") # there is no neumann_o3 + f.applyBoundary(boundary="free_o4", region="upper_target") + elif order==3: + if direction == "x": + f.applyBoundary(boundary="free_o5", region="core") + f.applyBoundary(boundary="free_o5", region="sol") + if direction == "y": + f.applyBoundary(boundary="free_o5", region="lower_target") + f.applyBoundary(boundary="free_o5", region="upper_target") + elif order==4: + if direction == "x": + f.applyBoundary(boundary="free_o5", region="core") + f.applyBoundary(boundary="free_o5", region="sol") + if direction == "y": + f.applyBoundary(boundary="free_o5", region="upper_target") + f.applyBoundary(boundary="free_o5", region="lower_target") + # don't have accurate enough boundary conditions, so reduce expected order + expected_order = 3 + else: + raise ValueError("don't know how to test a derivatives higher than d2/d*2") + #endif testBoundaries + sim=diff_func(f,method=diff,outloc=outloc) if sim.getLocation() != outloc: cent=['CENTRE','CENTER'] @@ -42,37 +152,50 @@ def runtests(functions,derivatives,directions,stag,msg): pass else: errorlist.append("Location does not match - expected %s but got %s"%(outloc,sim.getLocation())) - ana=boutcore.create3D(outfunc.replace("%s",dirnfac),mesh, outloc=outloc) + ana=boutcore.create3D(this_outfunc, mesh, outloc=outloc) err=sim-ana err=err.getAll().flatten() if guards: err=err[guards:-guards] - err=np.max(np.abs(err)) - errors.append(err) + if ("LOW" in inloc) and ("LOW" in outloc) and guards: + # first point is the one where the boundary condition is set on staggered fields + # the derivative at this point does not necessarily have to be + # accurate, since it is effectively an 'extra' guard cell + err=err[1:] + err_max=np.max(np.abs(err)) + errors.append(err_max) + err_L2=np.sqrt(np.mean(err**2)) + errors_L2.append(err_L2) errc=np.log(errors[-2]/errors[-1]) difc=np.log(nzs[-1]/nzs[-2]) conv=errc/difc - if order-.1 < conv < order+.1: + errc_L2=np.log(errors_L2[-2]/errors_L2[-1]) + conv_L2=errc_L2/difc + if expected_order-.2 < conv < expected_order+.2: pass else: info="%s - %s - %s - %s -> %s "%(infunc,diff, direction,inloc,outloc) - error="%s: %s is not working. Expected %f got %f"%(msg,info,order,conv) + error="%s: %s is not working with testBoundaries=%i. Expected %f got max error %f, RMS error %f"%(msg,info,testBoundaries,expected_order,conv,conv_L2) + print(error) errorlist.append(error) if doPlot: from matplotlib import pyplot as plt plt.plot((ana).getAll().flatten()) plt.plot((sim).getAll().flatten()) + plt.figure() + plt.legend() plt.show() -mmax=7 -start=6 +mmax=8 +start=7 doPlot=False nzs=np.logspace(start,mmax,num=mmax-start+1,base=2) +# functions contains list of triples of (function, derivative_operator(function), first_derivative(function) functions=[ - ["sin(%s)","cos(%s)"] , - ["cos(%s)", "-sin(%s)"] + ["sin(%s+1.)", "cos(%s+1.)", "cos(%s+1.)"] , + ["cos(%s+1.)", "-sin(%s+1.)", "-sin(%s+1.)"] ] derivatives=[ @@ -84,9 +207,9 @@ derivatives=[ ] directions=[ - ["x","2*pi",2 ,boutcore.DDX], - ["y","1" ,2 ,boutcore.DDY], -# ["z","1" ,0 ,boutcore.DDZ] + ["x","2*pi",2 ,boutcore.DDX, 1], + ["y","1" ,2 ,boutcore.DDY, 1], +# ["z","1" ,0 ,boutcore.DDZ, 1] ] runtests(functions,derivatives,directions,stag=False,msg="DD") @@ -100,8 +223,8 @@ runtests(functions,derivatives,directions,stag=True,msg="DD") functions=[ - ["sin(%s)","-sin(%s)"], - ["cos(%s)" , "-cos(%s)"] + ["sin(%s+1.)","-sin(%s+1.)", "cos(%s+1.)"], + ["cos(%s+1.)" , "-cos(%s+1.)", "-sin(%s+1.)"] ] derivatives=[ @@ -109,9 +232,9 @@ derivatives=[ [4,"C4"] ] directions=[ - ["x","2*pi",2 ,boutcore.D2DX2], - ["y","1" ,2 ,boutcore.D2DY2], -# ["z","1" ,0 ,boutcore.D2DZ2] + ["x","2*pi",2 ,boutcore.D2DX2, 2], + ["y","1" ,2 ,boutcore.D2DY2, 2], +# ["z","1" ,0 ,boutcore.D2DZ2, 2] ] runtests(functions,derivatives,directions,False,"D2D2") From 4d6a7e7f9fc17d64d33da3e2aabd828a63925d4d Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 21 Oct 2018 19:37:46 +0100 Subject: [PATCH 17/45] Add BoundaryDirichet_smooth Dirichlet boundary condition, tries to smooth out grid-scale oscillations at the boundary. Dirichlet bc using val and first grid point would be fb = 2*val - f0 using val and second grid point would be fb = 4/3*val - 1/3*f1 Here we apply the bc using the average of the two, to try and suppress grid-scale oscillations at the boundary. --- include/boundary_standard.hxx | 12 ++++++++++++ src/mesh/boundary_factory.cxx | 1 + src/mesh/boundary_standard.cxx | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/include/boundary_standard.hxx b/include/boundary_standard.hxx index 1961d81e30..d3b169a22c 100644 --- a/include/boundary_standard.hxx +++ b/include/boundary_standard.hxx @@ -59,6 +59,18 @@ class BoundaryDirichlet_O4 : public BoundaryOp { void extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) override; }; +/// Dirichlet boundary condition, tries to smooth out grid-scale oscillations at the boundary +class BoundaryDirichlet_smooth : public BoundaryOp { + public: + using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors + BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + + void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) override; + void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) override; +}; + /// Dirichlet boundary condition set half way between guard cell and grid cell at 2nd order accuracy class BoundaryDirichlet_2ndOrder : public BoundaryOp { public: diff --git a/src/mesh/boundary_factory.cxx b/src/mesh/boundary_factory.cxx index 3ac89764f4..e96d752448 100644 --- a/src/mesh/boundary_factory.cxx +++ b/src/mesh/boundary_factory.cxx @@ -20,6 +20,7 @@ BoundaryFactory::BoundaryFactory() { add(new BoundaryDirichlet_O4(), "dirichlet_o4"); add(new BoundaryDirichlet_O5(), "dirichlet_o5"); add(new BoundaryDirichlet_O5(), "dirichlet_4thorder"); // Synonym for "dirichlet_o5" + add(new BoundaryDirichlet_smooth(), "dirichlet_smooth"); add(new BoundaryNeumann(), "neumann"); add(new BoundaryNeumann(), "neumann_O2"); // Synonym for "neumann" add(new BoundaryNeumann2(), "neumann2"); // Deprecated diff --git a/src/mesh/boundary_standard.cxx b/src/mesh/boundary_standard.cxx index af838095fb..24815fa688 100644 --- a/src/mesh/boundary_standard.cxx +++ b/src/mesh/boundary_standard.cxx @@ -481,6 +481,38 @@ void BoundaryDirichlet_O4::extrapFurther(Field3D &f, int x, int bx, int y, int b /////////////////////////////////////////////////////////////// +BoundaryOp* BoundaryDirichlet_smooth::clone(BoundaryRegion *region, const list &args){ + verifyNumPoints(region, 2); + + std::shared_ptr newgen = nullptr; + if(!args.empty()) { + // First argument should be an expression + newgen = FieldFactory::get()->parse(args.front()); + } + return new BoundaryDirichlet_smooth(region, newgen); +} + +void BoundaryDirichlet_smooth::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = 5./3.*val - 0.5*f(x - bx, y - by, z) - 1./6.*f(x - 2*bx, y - 2*by, z); +} +void BoundaryDirichlet_smooth::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { + // Dirichlet bc using val and first grid point would be + // fb = 2*val - f0 + // using val and second grid point would be + // fb = 4/3*val - 1/3*f1 + // Here we apply the bc using the average of the two, to try and suppress + // grid-scale oscillations at the boundary + f(x, y, z) = 5./3.*val - 0.5*f(x - bx, y - by, z) - 1./6.*f(x - 2*bx, y - 2*by, z); +} + +void BoundaryDirichlet_smooth::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = val; +} +void BoundaryDirichlet_smooth::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) { + f(x, y, z) = val; +} +/////////////////////////////////////////////////////////////// + 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"; From 3cdb9641a0a81ab8df909a12216c1f4f2245d126 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 18 Oct 2018 12:21:14 +0100 Subject: [PATCH 18/45] Swap boundary conditions and test staggergrids=false in wave-1d Adds extra cases to runtest. Check both inner boundaries Neumann with outer boundaries Dirichlet and the opposite way round. Check true and false for mesh:staggergrids. --- tests/MMS/wave-1d/data/BOUT.inp | 6 +- tests/MMS/wave-1d/runtest | 138 ++++++++++++++++++-------------- tests/MMS/wave-1d/wave.cxx | 57 ++++++++----- 3 files changed, 118 insertions(+), 83 deletions(-) diff --git a/tests/MMS/wave-1d/data/BOUT.inp b/tests/MMS/wave-1d/data/BOUT.inp index bcadb4eab4..9388cce9d0 100644 --- a/tests/MMS/wave-1d/data/BOUT.inp +++ b/tests/MMS/wave-1d/data/BOUT.inp @@ -75,13 +75,11 @@ zs_opt = 0 [f] -bndry_all = neumann # Should be ignored -bndry_xin = neumann_o2 +bndry_all = none [g] -bndry_all = dirichlet_o2 -bndry_xin = neumann # Should have no effect +bndry_all = none ################################ diff --git a/tests/MMS/wave-1d/runtest b/tests/MMS/wave-1d/runtest index f400d919c2..d677428c6d 100755 --- a/tests/MMS/wave-1d/runtest +++ b/tests/MMS/wave-1d/runtest @@ -22,88 +22,104 @@ shell_safe("make > make.log") # List of NX values to use nxlist = [8, 12, 20, 36, 68, 132] +# switch staggered grids on/off, swap the boundary conditions in<->out +optslist = [" f:bndry_xout=dirichlet_smooth f:bndry_all=neumann g:bndry_xout=dirichlet_smooth g:bndry_all=neumann", + " mesh:staggergrids=false f:bndry_xout=dirichlet_smooth f:bndry_all=neumann g:bndry_xout=dirichlet_smooth g:bndry_all=neumann", + " swap_boundary_conditions=true f:bndry_xin=dirichlet_smooth f:bndry_all=neumann g:bndry_xin=dirichlet_smooth g:bndry_all=neumann", + " mesh:staggergrids=false, swap_boundary_conditions=true f:bndry_xin=dirichlet_smooth f:bndry_all=neumann g:bndry_xin=dirichlet_smooth g:bndry_all=neumann"] nout = 1 timestep = 0.1 nproc = 1 -error_2 = [] # The L2 error (RMS) -error_inf = [] # The maximum error +results = [] +for iopt,opts in enumerate(optslist): + error_2 = [] # The L2 error (RMS) + error_inf = [] # The maximum error -for nx in nxlist: - args = "mesh:nx="+str(nx)+" nout="+str(nout)+" timestep="+str(timestep) - - print("Running with " + args) + print("opts = '"+opts+"'\n") - # Delete old data - shell("rm data/BOUT.dmp.*.nc") - - # Command to run - cmd = "./wave "+args - # Launch using MPI - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) + for nx in nxlist: + args = "mesh:nx="+str(nx)+" nout="+str(nout)+" timestep="+str(timestep)+opts - # Save output to log file - f = open("run.log."+str(nx), "w") - f.write(out) - f.close() + print("Running with " + args) - # Collect data - E_f = collect("E_f", tind=[nout,nout], path="data", info=False) - E_f = E_f[0,:,0,0] - - E_g = collect("E_g", tind=[nout,nout], path="data", info=False) - E_g = E_g[0,:,0,0] + # Delete old data + shell("rm data/BOUT.dmp.*.nc") - # Average error over domain, not including guard cells - E = concatenate([E_f[1:-1], E_g[2:-1]]) + # Command to run + cmd = "./wave "+args + # Launch using MPI + s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) - l2 = sqrt(mean(E**2)) - linf = max(abs(E)) - - error_2.append( l2 ) - error_inf.append( linf ) + # Save output to log file + f = open("run.log."+str(iopt)+"."+str(nx), "w") + f.write(out) + f.close() - print("Error norm: l-2 %f l-inf %f" % (l2, linf)) + # Collect data + E_f = collect("E_f", path="data", info=False) + E_f = E_f[-1,:,0,0] -# Calculate grid spacing -dx = 1. / (array(nxlist) - 2.) + E_g = collect("E_g", path="data", info=False) + E_g = E_g[-1,:,0,0] -order = log(error_2[-1] / error_2[-2]) / log(dx[-1] / dx[-2]) -print("Convergence order = %f" % (order)) + # Average error over domain, not including guard cells + E = concatenate([E_f[1:-1], E_g[2:-1]]) -# plot errors -try: - import matplotlib.pyplot as plt + l2 = sqrt(mean(E**2)) + linf = max(abs(E)) - plt.plot(dx, error_2, '-o', label=r'$l^2$') - plt.plot(dx, error_inf, '-x', label=r'$l^\infty$') - plt.plot(dx, error_2[-1]*(dx/dx[-1])**order, '--', label="Order %.1f"%(order)) + error_2.append( l2 ) + error_inf.append( linf ) - plt.legend(loc="upper left") - plt.grid() + print("Error norm: l-2 %f l-inf %f" % (l2, linf)) - plt.yscale('log') - plt.xscale('log') + # Calculate grid spacing + dx = 1. / (array(nxlist) - 2.) - plt.xlabel(r'Mesh spacing $\delta x$') - plt.ylabel("Error norm") + order = log(error_2[-1] / error_2[-2]) / log(dx[-1] / dx[-2]) + print("Convergence order = %f" % (order)) - plt.savefig("wave_norm.pdf") + # plot errors + try: + import matplotlib.pyplot as plt - #plt.show() - plt.close() -except: - # Plotting could fail for any number of reasons, and the actual - # error raised may depend on, among other things, the current - # matplotlib backend, so catch everything - pass + plt.plot(dx, error_2, '-o', label=r'$l^2$') + plt.plot(dx, error_inf, '-x', label=r'$l^\infty$') + plt.plot(dx, error_2[-1]*(dx/dx[-1])**order, '--', label="Order %.1f"%(order)) + + plt.legend(loc="upper left") + plt.grid() + + plt.yscale('log') + plt.xscale('log') + + plt.xlabel(r'Mesh spacing $\delta x$') + plt.ylabel("Error norm") + + plt.savefig("wave_norm.pdf") + + #plt.show() + plt.close() + except: + # Plotting could fail for any number of reasons, and the actual + # error raised may depend on, among other things, the current + # matplotlib backend, so catch everything + pass + + if 2.2 > order > 1.8: + # test for success + results.append(0) + else: + results.append(1) + + print("") -if 2.2 > order > 1.8: - # test for success - print(" => Test passed") - exit(0) +if all(r == 0 for r in results): + print(" => Test passed") + exit(0) else: - print(" => Test failed") - exit(1) + print(" => Test failed") + exit(1) diff --git a/tests/MMS/wave-1d/wave.cxx b/tests/MMS/wave-1d/wave.cxx index d2543a98b1..d37c0b12dc 100644 --- a/tests/MMS/wave-1d/wave.cxx +++ b/tests/MMS/wave-1d/wave.cxx @@ -42,7 +42,11 @@ class Wave1D : public PhysicsModel { Field3D f, g; // Evolving variables Field3D E_f, E_g; // Error vectors + bool swap_boundary_conditions; + Coordinates *coord; + + CELL_LOC maybe_xlow = mesh->StaggerGrids ? CELL_XLOW : CELL_CENTRE; const Field3D solution_f(BoutReal t); const Field3D source_f(BoutReal t); @@ -56,6 +60,8 @@ class Wave1D : public PhysicsModel { // Get the options Options *meshoptions = Options::getRoot()->getSection("mesh"); + + OPTION(Options::getRoot(), swap_boundary_conditions, false); meshoptions->get("Lx",Lx,1.0); meshoptions->get("Ly",Ly,1.0); @@ -83,14 +89,29 @@ class Wave1D : public PhysicsModel { coord->g_23 = 0.0; coord->geometry(); - g.setLocation(CELL_XLOW); // g staggered to the left of f + g.setLocation(maybe_xlow); // g staggered to the left of f - //Dirichlet everywhere except inner x-boundary Neumann - f.addBndryFunction(MS_f,BNDRY_ALL); - f.addBndryFunction(dxMS_f,BNDRY_XIN); + // Note, when staggergrids=true, only g's boundary conditions have any effect + + if (!swap_boundary_conditions) { + // Dirichlet at outer x-boundary, Neumann everywhere else + f.addBndryFunction(dxMS_f,BNDRY_ALL); + f.addBndryFunction(MS_f,BNDRY_XOUT); // note order matters, must add this after BNDRY_ALL + } else { + // Dirichlet at inner x-boundary, Neumann everywhere else + f.addBndryFunction(dxMS_f,BNDRY_ALL); + f.addBndryFunction(MS_f,BNDRY_XIN); // note order matters, must add this after BNDRY_ALL + } - g.addBndryFunction(MS_g,BNDRY_ALL); - g.addBndryFunction(dxMS_g,BNDRY_XIN); + if (!swap_boundary_conditions) { + // Dirichlet at outer x-boundary, Neumann everywhere else + g.addBndryFunction(dxMS_g,BNDRY_ALL); + g.addBndryFunction(MS_g,BNDRY_XOUT); // note order matters, must add this after BNDRY_ALL + } else { + // Dirichlet at inner x-boundary, Neumann everywhere else + g.addBndryFunction(dxMS_g,BNDRY_ALL); + g.addBndryFunction(MS_g,BNDRY_XIN); // note order matters, must add this after BNDRY_ALL + } // Tell BOUT++ to solve f and g bout_solve(f, "f"); @@ -101,8 +122,8 @@ class Wave1D : public PhysicsModel { for (int xi = mesh->xstart; xi < mesh->xend +1; xi++){ for (int yj = mesh->ystart; yj < mesh->yend + 1; yj++){ for (int zk = 0; zk < mesh->LocalNz; zk++) { - f(xi, yj, zk) = MS_f(0.,mesh->GlobalX(xi),mesh->GlobalY(yj),coord->dz*zk); - g(xi, yj, zk) = MS_g(0.,0.5*(mesh->GlobalX(xi)+mesh->GlobalX(xi-1)),mesh->GlobalY(yj),coord->dz*zk); + f(xi, yj, zk) = MS_f(0.,mesh->GlobalX(xi),TWOPI*mesh->GlobalY(yj),TWOPI*coord->dz*zk); + g(xi, yj, zk) = MS_g(0.,0.5*(mesh->GlobalX(xi)+mesh->GlobalX(xi-1)),TWOPI*mesh->GlobalY(yj),TWOPI*coord->dz*zk); } } } @@ -110,8 +131,8 @@ class Wave1D : public PhysicsModel { for (int xi = mesh->xstart; xi < mesh->xend +1; xi++){ for (int yj = mesh->ystart; yj < mesh->yend + 1; yj++){ for (int zk = 0; zk < mesh->LocalNz; zk++) { - f(xi, yj, zk) = MS_f(0.,mesh->GlobalX(xi),mesh->GlobalY(yj),coord->dz*zk); - g(xi, yj, zk) = MS_g(0.,mesh->GlobalX(xi),mesh->GlobalY(yj),coord->dz*zk); + f(xi, yj, zk) = MS_f(0.,mesh->GlobalX(xi),TWOPI*mesh->GlobalY(yj),TWOPI*coord->dz*zk); + g(xi, yj, zk) = MS_g(0.,mesh->GlobalX(xi),TWOPI*mesh->GlobalY(yj),TWOPI*coord->dz*zk); } } } @@ -135,8 +156,8 @@ class Wave1D : public PhysicsModel { //ddt(g) = HLL(-f, g, -1.0, 1.0); // Central differencing - ddt(f) = DDX(g, CELL_CENTRE);// + 20*SQ(coord->dx)*D2DX2(f); - ddt(g) = DDX(f, CELL_XLOW);// + 20*SQ(coord->dx)*D2DX2(g); + ddt(f) = DDX(g, CELL_CENTRE);// + 20*SQ(f.getCoordinates()->dx)*D2DX2(f); + ddt(g) = DDX(f, maybe_xlow);// + 20*SQ(g.getCoordinates()->dx)*D2DX2(g); //add MMS source term ddt(f) += source_f(t); @@ -198,10 +219,10 @@ const Field3D Wave1D::solution_f(BoutReal t) { for (int xi = mesh->xstart - bx; xi < mesh->xend + bx + 1; xi++){ for (int yj = mesh->ystart - by; yj < mesh->yend + by + 1; yj++){ BoutReal x = mesh->GlobalX(xi); - BoutReal y = mesh->GlobalY(yj);//GlobalY not fixed yet + BoutReal y = mesh->GlobalY(yj); for (int zk = 0; zk < mesh->LocalNz; zk++) { BoutReal z = coord->dz*zk; - S(xi, yj, zk) = MS_f(t,x,y,z); + S(xi, yj, zk) = MS_f(t,x,TWOPI*y,TWOPI*z); } } } @@ -249,7 +270,7 @@ const Field3D Wave1D::solution_g(BoutReal t) { Field3D S; S.allocate(); - S.setLocation(CELL_XLOW); + S.setLocation(maybe_xlow); int bx = (mesh->LocalNx - (mesh->xend - mesh->xstart + 1)) / 2; int by = (mesh->LocalNy - (mesh->yend - mesh->ystart + 1)) / 2; @@ -260,10 +281,10 @@ const Field3D Wave1D::solution_g(BoutReal t) { if(mesh->StaggerGrids) { x = 0.5*(mesh->GlobalX(xi-1) + mesh->GlobalX(xi)); } - BoutReal y = mesh->GlobalY(yj);//GlobalY not fixed yet + BoutReal y = mesh->GlobalY(yj); for (int zk = 0; zk < mesh->LocalNz; zk++) { BoutReal z = coord->dz*zk; - S(xi, yj, zk) = MS_g(t,x,y,z); + S(xi, yj, zk) = MS_g(t,x,TWOPI*y,TWOPI*z); } } } @@ -275,7 +296,7 @@ const Field3D Wave1D::source_g(BoutReal t) { Field3D result; result.allocate(); - result.setLocation(CELL_XLOW); + result.setLocation(maybe_xlow); int xi,yj,zk; From 6e4de0f11090e1485cfc302358be68dd05adfcf0 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 21 Oct 2018 17:36:11 +0100 Subject: [PATCH 19/45] Test StaggerGrids=false and both dirichlet_smooth/neumann in MMS/wave-1d-y --- tests/MMS/wave-1d-y/data/BOUT.inp | 5 +- tests/MMS/wave-1d-y/runtest | 166 ++++++++++++++++-------------- tests/MMS/wave-1d-y/wave.cxx | 13 ++- 3 files changed, 99 insertions(+), 85 deletions(-) diff --git a/tests/MMS/wave-1d-y/data/BOUT.inp b/tests/MMS/wave-1d-y/data/BOUT.inp index d47b8d9df8..f375e905a6 100644 --- a/tests/MMS/wave-1d-y/data/BOUT.inp +++ b/tests/MMS/wave-1d-y/data/BOUT.inp @@ -67,15 +67,14 @@ solution = y - sin(t)*cos(0.5*y) + cos(y) ddy = 0.5*sin(t)*sin(0.5*y) - sin(y) + 1 source = 0.2*y*sin(0.1*y^2)*cos(t) - 2*y - cos(t)*cos(0.5*y) - cos(y) -bndry_all = neumann_o2(f:ddy) -bndry_yup = dirichlet_o2(f:solution) +bndry_all = none [g] solution = y^2 + sin(y) + cos(t)*cos(0.1*y^2) ddy = -0.2*y*sin(0.1*y^2)*cos(t) + 2*y + cos(y) source = -0.5*sin(t)*sin(0.5*y) - sin(t)*cos(0.1*y^2) + sin(y) - 1 -bndry_all = dirichlet_o2(g:solution) +bndry_all = none ################################ diff --git a/tests/MMS/wave-1d-y/runtest b/tests/MMS/wave-1d-y/runtest index 168cea6807..6d5dde19cb 100755 --- a/tests/MMS/wave-1d-y/runtest +++ b/tests/MMS/wave-1d-y/runtest @@ -24,9 +24,16 @@ MPIRUN = getmpirun() print("Making MMS wave test") shell_safe("make > make.log") -# List of NX values to use +# List of NY values to use nylist = [8, 16, 32, 64, 128, 256] +# Options to test +opts_list = [' mesh:staggergrids=true f:bndry_ydown="dirichlet_smooth(f:solution)" f:bndry_yup="dirichlet_smooth(f:solution)" g:bndry_ydown="dirichlet_smooth(g:solution)" g:bndry_yup="dirichlet_smooth(g:solution)"', + ' mesh:staggergrids=true f:bndry_ydown="neumann(f:ddy)" f:bndry_yup="neumann(f:ddy)" g:bndry_ydown="neumann(g:ddy)" g:bndry_yup="neumann(g:ddy)"', + ' mesh:staggergrids=false f:bndry_ydown="dirichlet_smooth(f:solution)" f:bndry_yup="dirichlet_smooth(f:solution)" g:bndry_ydown="dirichlet_smooth(g:solution)" g:bndry_yup="dirichlet_smooth(g:solution)"', + ' mesh:staggergrids=false f:bndry_ydown="neumann(f:ddy)" f:bndry_yup="neumann(f:ddy)" g:bndry_ydown="neumann(g:ddy)" g:bndry_yup="neumann(g:ddy)"'] + + nout = 1 timestep = 1 @@ -36,91 +43,92 @@ varlist = ["f", "g"] markers = ['bo', 'r^'] labels = ["f", "g"] -error_2 = {} -error_inf = {} -for var in varlist: - error_2[var] = [] # The L2 error (RMS) - error_inf[var] = [] # The maximum error - -for ny in nylist: - dy = 2.*pi / ny - args = "mesh:ny="+str(ny)+" mesh:dy="+str(dy)+" nout="+str(nout)+" timestep="+str(timestep) - - print("Running with " + args) - - # Delete old data - shell("rm data/BOUT.dmp.*.nc") - - # Command to run - cmd = "./wave "+args - # Launch using MPI - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) - - # Save output to log file - with open("run.log."+str(ny), "w") as f: - f.write(out) - - for var in varlist: - # Collect data - E = collect("E_"+var, tind=[nout,nout], info=False, path="data") - E = E[0,0,:,0] - - # Average error over domain - - l2 = sqrt(mean(E**2)) - linf = max(abs(E)) - - error_2[var].append( l2 ) - error_inf[var].append( linf ) - - print("Error norm %s: l-2 %f l-inf %f" % (var, l2, linf)) - -# Save data -with open("wave.pkl", "wb") as output: - pickle.dump(nylist, output) - pickle.dump(error_2, output) - pickle.dump(error_inf, output) - -# Calculate grid spacing -dy = 1. / array(nylist) - -# Calculate convergence order success = True -for var in varlist: - order = log(error_2[var][-1] / error_2[var][-2]) / log(dy[-1] / dy[-2]) - stdout.write("%s Convergence order = %f" % (var, order)) - - if 1.8 < order < 2.2: # Should be second order accurate - print("............ PASS") - else: - success = False - print("............ FAIL") +for i,opts in enumerate(opts_list): + error_2 = {} + error_inf = {} + for var in varlist: + error_2[var] = [] # The L2 error (RMS) + error_inf[var] = [] # The maximum error -# plot errors -try: - import matplotlib.pyplot as plt - for var,mark,label in zip(varlist, markers, labels): - plt.plot(dy, error_2[var], '-'+mark, label="%s order=%.2f" % (label, order)) - plt.plot(dy, error_inf[var], '--'+mark) + for ny in nylist: + dy = 2.*pi / ny + args = "mesh:ny="+str(ny)+" mesh:dy="+str(dy)+" nout="+str(nout)+" timestep="+str(timestep)+opts + + print("Running with " + args) - plt.legend(loc="upper left") - plt.grid() + # Delete old data + shell("rm data/BOUT.dmp.*.nc") + + # Command to run + cmd = "./wave "+args + # Launch using MPI + s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) + + # Save output to log file + with open("run.log."+str(ny), "w") as f: + f.write(out) + + for var in varlist: + # Collect data + E = collect("E_"+var, tind=[nout,nout], info=False, path="data") + E = E[0,0,:,0] + + # Average error over domain + + l2 = sqrt(mean(E**2)) + linf = max(abs(E)) + + error_2[var].append( l2 ) + error_inf[var].append( linf ) - plt.yscale('log') - plt.xscale('log') + print("Error norm %s: l-2 %f l-inf %f" % (var, l2, linf)) - plt.xlabel(r'Mesh spacing $\delta y$') - plt.ylabel("Error norm") + ## Save data + #with open("wave.pkl", "wb") as output: + # pickle.dump(nylist, output) + # pickle.dump(error_2, output) + # pickle.dump(error_inf, output) - plt.savefig("norm.pdf") + # Calculate grid spacing + dy = 1. / array(nylist) - #plt.show() - plt.close() -except: - # Plotting could fail for any number of reasons, and the actual - # error raised may depend on, among other things, the current - # matplotlib backend, so catch everything - pass + # Calculate convergence order + for var in varlist: + order = log(error_2[var][-1] / error_2[var][-2]) / log(dy[-1] / dy[-2]) + stdout.write("%s Convergence order = %f" % (var, order)) + + if 1.8 < order < 2.2: # Should be second order accurate + print("............ PASS with", opts) + else: + success = False + print("............ FAIL with", opts) + + # plot errors + try: + import matplotlib.pyplot as plt + for var,mark,label in zip(varlist, markers, labels): + plt.plot(dy, error_2[var], '-'+mark, label="%s order=%.2f" % (label, order)) + plt.plot(dy, error_inf[var], '--'+mark) + + plt.legend(loc="upper left") + plt.grid() + + plt.yscale('log') + plt.xscale('log') + + plt.xlabel(r'Mesh spacing $\delta y$') + plt.ylabel("Error norm") + + plt.savefig("norm%i.pdf"%i) + + #plt.show() + plt.close() + except: + # Plotting could fail for any number of reasons, and the actual + # error raised may depend on, among other things, the current + # matplotlib backend, so catch everything + pass if success: print(" => Test passed") diff --git a/tests/MMS/wave-1d-y/wave.cxx b/tests/MMS/wave-1d-y/wave.cxx index db4c931665..6fe8896896 100644 --- a/tests/MMS/wave-1d-y/wave.cxx +++ b/tests/MMS/wave-1d-y/wave.cxx @@ -5,12 +5,19 @@ class Wave1D : public PhysicsModel { private: Field3D f, g; // Evolving variables + CELL_LOC maybe_ylow; protected: int init(bool restarting) { - g.setLocation(CELL_YLOW); // g staggered - + if(mesh->StaggerGrids) { + maybe_ylow = CELL_YLOW; + } else { + maybe_ylow = CELL_CENTRE; + } + + g.setLocation(maybe_ylow); // g staggered + // Tell BOUT++ to solve f and g bout_solve(f, "f"); bout_solve(g, "g"); @@ -23,7 +30,7 @@ class Wave1D : public PhysicsModel { // Central differencing ddt(f) = DDY(g, CELL_CENTRE); - ddt(g) = DDY(f, CELL_YLOW); + ddt(g) = DDY(f, maybe_ylow); return 0; } From cf7aa24b0ee2870623cb398fb22dd81b34b7b0a8 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 21 Oct 2018 19:29:07 +0100 Subject: [PATCH 20/45] Use dirichlet and neumann in MMS/diffusion --- tests/MMS/diffusion/data/BOUT.inp | 3 +- tests/MMS/diffusion/diffusion.cxx | 13 ++-- tests/MMS/diffusion/runtest | 101 +++++++++++++++--------------- 3 files changed, 60 insertions(+), 57 deletions(-) diff --git a/tests/MMS/diffusion/data/BOUT.inp b/tests/MMS/diffusion/data/BOUT.inp index b4ec84fb8f..6989c8a4fe 100644 --- a/tests/MMS/diffusion/data/BOUT.inp +++ b/tests/MMS/diffusion/data/BOUT.inp @@ -67,6 +67,7 @@ mxstep = 1000000 [cyto] dis = 1 +neumann_boundaries = false [all] @@ -78,7 +79,5 @@ zs_opt = 0 [N] -bndry_all = dirichlet_o2 -bndry_xin = neumann_o2 ################################ diff --git a/tests/MMS/diffusion/diffusion.cxx b/tests/MMS/diffusion/diffusion.cxx index b89a0b0e6a..a3aa592d81 100644 --- a/tests/MMS/diffusion/diffusion.cxx +++ b/tests/MMS/diffusion/diffusion.cxx @@ -42,6 +42,8 @@ int physics_init(bool restarting) { Options *cytooptions = Options::getRoot()->getSection("cyto"); cytooptions->get("dis", mu_N, 1); + bool neumann_boundaries; + cytooptions->get("neumann_boundaries", neumann_boundaries, false); SAVE_ONCE(mu_N); @@ -61,12 +63,11 @@ int physics_init(bool restarting) { coord->g_23 = 0.0; coord->geometry(); - //Dirichlet everywhere except inner x-boundary Neumann - N.addBndryFunction(MS,BNDRY_ALL); - N.addBndryFunction(dxMS,BNDRY_XIN); - - //Dirichlet boundary conditions everywhere - //N.addBndryFunction(MS,BNDRY_ALL); + if (neumann_boundaries) { + N.addBndryFunction(dxMS,BNDRY_ALL); + } else { + N.addBndryFunction(MS,BNDRY_ALL); + } // Tell BOUT++ to solve N SOLVE_FOR(N); diff --git a/tests/MMS/diffusion/runtest b/tests/MMS/diffusion/runtest index 5c8b35eb85..a74eec2b8f 100755 --- a/tests/MMS/diffusion/runtest +++ b/tests/MMS/diffusion/runtest @@ -21,6 +21,8 @@ shell_safe("make > make.log") # List of NX values to use nxlist = [4, 8, 16, 32, 64, 128] +opts_list = [" cyto:neumann_boundaries=false n:bndry_xin=dirichlet n:bndry_xout=dirichlet", + " cyto:neumann_boundaries=true N:bndry_xin=neumann N:bndry_xout=neumann"] nout = 1 timestep = 0.1 @@ -30,70 +32,71 @@ nproc = 1 error_2 = [] # The L2 error (RMS) error_inf = [] # The maximum error -for nx in nxlist: - args = "mesh:nx="+str(nx)+" nout="+str(nout)+" timestep="+str(timestep) - - print("Running with " + args) +for i,opts in enumerate(opts_list): + for nx in nxlist: + args = "mesh:nx="+str(nx)+" nout="+str(nout)+" timestep="+str(timestep)+opts - # Delete old data - shell("rm data/BOUT.dmp.*.nc") - - # Command to run - cmd = "./cyto "+args - # Launch using MPI - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) + print("Running with " + args) - # Save output to log file - f = open("run.log."+str(nx), "w") - f.write(out) - f.close() + # Delete old data + shell("rm data/BOUT.dmp.*.nc") - # Collect data - E_N = collect("E_N", tind=[nout,nout], path="data", info=False) + # Command to run + cmd = "./cyto "+args + # Launch using MPI + s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) - E_N = E_N[0,:,0,0] + # Save output to log file + f = open("run.log."+str(nx), "w") + f.write(out) + f.close() - # Average error over domain, not including guard cells - l2 = sqrt(mean(E_N[1:-1]**2)) - linf = max(abs( E_N[1:-1] )) - - error_2.append( l2 ) - error_inf.append( linf ) + # Collect data + E_N = collect("E_N", tind=[nout,nout], path="data", info=False) - print("Error norm: l-2 %f l-inf %f" % (l2, linf)) + E_N = E_N[0,:,0,0] -# Calculate grid spacing -dx = 1. / (array(nxlist) - 2.) + # Average error over domain, not including guard cells + l2 = sqrt(mean(E_N[1:-1]**2)) + linf = max(abs( E_N[1:-1] )) -order = log(error_2[-1] / error_2[-2]) / log(dx[-1] / dx[-2]) -print("Convergence order = %f" % (order)) + error_2.append( l2 ) + error_inf.append( linf ) -# Attempt to plot errors -try: - import matplotlib.pyplot as plt + print("Error norm: l-2 %f l-inf %f" % (l2, linf)) - plt.plot(dx, error_2, '-o', label=r'$l^2$') - plt.plot(dx, error_inf, '-x', label=r'$l^\infty$') - plt.plot(dx, error_2[-1]*(dx/dx[-1])**order, '--', label="Order %.1f"%(order)) + # Calculate grid spacing + dx = 1. / (array(nxlist) - 2.) - plt.legend(loc="upper left") - plt.grid() + order = log(error_2[-1] / error_2[-2]) / log(dx[-1] / dx[-2]) + print("Convergence order = %f" % (order)) - plt.yscale('log') - plt.xscale('log') + # Attempt to plot errors + try: + import matplotlib.pyplot as plt - plt.xlabel(r'Mesh spacing $\delta x$') - plt.ylabel("Error norm") + plt.plot(dx, error_2, '-o', label=r'$l^2$') + plt.plot(dx, error_inf, '-x', label=r'$l^\infty$') + plt.plot(dx, error_2[-1]*(dx/dx[-1])**order, '--', label="Order %.1f"%(order)) - plt.savefig("norm.pdf") + plt.legend(loc="upper left") + plt.grid() - #plt.show() - plt.close() -except: - # Plotting could fail for any number of reasons, and the actual - # error raised may depend on, among other things, the current - # matplotlib backend, so catch everything - pass + plt.yscale('log') + plt.xscale('log') + + plt.xlabel(r'Mesh spacing $\delta x$') + plt.ylabel("Error norm") + + plt.savefig("norm.pdf") + + #plt.show() + plt.close() + except: + # Plotting could fail for any number of reasons, and the actual + # error raised may depend on, among other things, the current + # matplotlib backend, so catch everything + pass if order > 1.8 and order < 2.2: # test for success From 9f09ab8afeb80613f49ac414216d7c0c879dc9b6 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 22 Oct 2018 11:25:16 +0100 Subject: [PATCH 21/45] Throw exceptions with helpful error messages. BoundaryOp::applyAtPoint() and BoundaryOp::applyAtPointStaggered() should never be called, but must be implemented in the base class in case a subclass overrides BoundaryOp::apply() and so does not need these methods. This commit provides a helpful error message if these methods are ever called, instead of the previous ASSERT1(false). --- include/boundary_op.hxx | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/include/boundary_op.hxx b/include/boundary_op.hxx index a10173d804..55f7f3f396 100644 --- a/include/boundary_op.hxx +++ b/include/boundary_op.hxx @@ -74,24 +74,32 @@ protected: virtual void applyAtPoint(Field2D &UNUSED(f), BoutReal UNUSED(val), int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), Coordinates* UNUSED(metric)) { - ASSERT1(false); + throw BoutException("BoundaryOp::applyAtPoint() should never be called. A " + "subclass should either override BoundaryOp::apply() or override " + "applyAtPoint() and applyAtPointStaggered()."); } virtual void applyAtPoint(Field3D &UNUSED(f), BoutReal UNUSED(val), int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), Coordinates* UNUSED(metric)) { - ASSERT1(false); + throw BoutException("BoundaryOp::applyAtPoint() should never be called. A " + "subclass should either override BoundaryOp::apply() or override " + "applyAtPoint() and applyAtPointStaggered()."); } // Apply to staggered grid virtual void applyAtPointStaggered(Field2D &UNUSED(f), BoutReal UNUSED(val), int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), Coordinates* UNUSED(metric)) { - ASSERT1(false); + throw BoutException("BoundaryOp::applyAtPointStaggered() should never be " + "called. A subclass should either override BoundaryOp::apply() or " + "override applyAtPoint() and applyAtPointStaggered()."); } virtual void applyAtPointStaggered(Field3D &UNUSED(f), BoutReal UNUSED(val), int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), Coordinates* UNUSED(metric)) { - ASSERT1(false); + throw BoutException("BoundaryOp::applyAtPointStaggered() should never be " + "called. A subclass should either override BoundaryOp::apply() or " + "override applyAtPoint() and applyAtPointStaggered()."); } // extrapolate to further guard cells From 9cde433671056638dc10816cf4cde45f178f7b74 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 22 Oct 2018 11:40:23 +0100 Subject: [PATCH 22/45] Remove redundant template arguments These were not needed because the compiler can infer the template arguments from the type (Field2D/Field3D) of the function argument. --- include/boundary_op.hxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boundary_op.hxx b/include/boundary_op.hxx index 55f7f3f396..3ac73df979 100644 --- a/include/boundary_op.hxx +++ b/include/boundary_op.hxx @@ -36,10 +36,10 @@ public: /// Apply a boundary condition on field f virtual void apply(Field2D &f,BoutReal t = 0.) { - applyTemplate(f, t); + applyTemplate(f, t); } virtual void apply(Field3D &f,BoutReal t = 0.) { - applyTemplate(f, t); + applyTemplate(f, t); } virtual void apply(Vector2D &f) { From febbe8ececa207a30205e2c912d9a215ed357080 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 29 Oct 2018 14:12:42 +0000 Subject: [PATCH 23/45] Suggest using 'auto' in boundary_factory.hxx docstring example code --- include/boundary_factory.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boundary_factory.hxx b/include/boundary_factory.hxx index e59fb681cf..ba1209367d 100644 --- a/include/boundary_factory.hxx +++ b/include/boundary_factory.hxx @@ -61,7 +61,7 @@ using BoundaryRegionOp = typename std::conditionalcreate("myboundary()", new BoundaryRegionXOut("xout", 0, 10, localmesh)); + * auto *bndry = bf->create("myboundary()", new BoundaryRegionXOut("xout", 0, 10, localmesh)); * * where the region is defined in boundary_region.hxx * From efb75e8c64024d720ec54fdefea6a3cf9ed59479 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 29 Oct 2018 14:19:03 +0000 Subject: [PATCH 24/45] Rename extrap* -> extrapolate* --- include/boundary_op.hxx | 4 +- include/boundary_standard.hxx | 32 +++++----- src/mesh/boundary_op.cxx | 20 +++---- src/mesh/boundary_standard.cxx | 104 ++++++++++++++++----------------- 4 files changed, 80 insertions(+), 80 deletions(-) diff --git a/include/boundary_op.hxx b/include/boundary_op.hxx index 3ac73df979..6ded78a276 100644 --- a/include/boundary_op.hxx +++ b/include/boundary_op.hxx @@ -103,8 +103,8 @@ protected: } // extrapolate to further guard cells - virtual void extrapFurther(Field2D &f, int x, int bx, int y, int by, int z); - virtual void extrapFurther(Field3D &f, int x, int bx, int y, int by, int z); + virtual void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); + virtual void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); private: template diff --git a/include/boundary_standard.hxx b/include/boundary_standard.hxx index d3b169a22c..4f582bf9c4 100644 --- a/include/boundary_standard.hxx +++ b/include/boundary_standard.hxx @@ -41,8 +41,8 @@ class BoundaryDirichlet_O3 : public BoundaryOp { void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) override; void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) override; - void extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) override; - void extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) override; + void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) override; + void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) override; }; /// 4th-order boundary condition @@ -55,8 +55,8 @@ class BoundaryDirichlet_O4 : public BoundaryOp { void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) override; void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) override; - void extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) override; - void extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) override; + void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) override; + void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) override; }; /// Dirichlet boundary condition, tries to smooth out grid-scale oscillations at the boundary @@ -93,8 +93,8 @@ class BoundaryDirichlet_O5 : public BoundaryOp { void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) override; void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) override; - void extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) override; - void extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) override; + void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) override; + void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) override; }; /// Neumann (zero-gradient) boundary condition for non-orthogonal meshes @@ -165,8 +165,8 @@ class BoundaryNeumann_O4 : public BoundaryOp { void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) override; - void extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) override; + void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) override; + void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) override; }; /// Neumann boundary condition set half way between guard cell and grid cell at 4th order accuracy @@ -179,8 +179,8 @@ class BoundaryNeumann_4thOrder : public BoundaryOp { void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) override; - void extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) override; + void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) override; + void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) override; }; /// NeumannPar (zero-gradient) boundary condition on @@ -319,8 +319,8 @@ public: void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) override; - void extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) override; + void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) override; + void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) override; }; // End L.Easy @@ -333,8 +333,8 @@ public: void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) override; - void extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) override; + void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) override; + void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) override; }; class BoundaryFree_O5 : public BoundaryOp { @@ -346,8 +346,8 @@ public: void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) override; - void extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) override; + void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) override; + void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) override; }; ///////////////////////////////////////////////////////// diff --git a/src/mesh/boundary_op.cxx b/src/mesh/boundary_op.cxx index e6f05b2b40..227c8fd3a8 100644 --- a/src/mesh/boundary_op.cxx +++ b/src/mesh/boundary_op.cxx @@ -24,10 +24,10 @@ #include #include -void BoundaryOp::extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) { +void BoundaryOp::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { f(x, y, z) = 2.0*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z); } -void BoundaryOp::extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) { +void BoundaryOp::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { f(x, y, z) = 2.0*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z); } @@ -74,7 +74,7 @@ void BoundaryOp::applyTemplate(T &f,BoutReal t) { for (int i = 1; i < bndry->width; i++) { int x = bndry->x + i*bndry->bx; int y = bndry->y + i*bndry->by; - extrapFurther(f, x, bndry->bx, y, bndry->by, z); + extrapolateFurther(f, x, bndry->bx, y, bndry->by, z); } } } @@ -97,7 +97,7 @@ void BoundaryOp::applyTemplate(T &f,BoutReal t) { // Need to set second guard cell, as may be used for interpolation or upwinding derivatives for (int i = 1; i < bndry->width; i++) { int x = bndry->x + i*bndry->bx; - extrapFurther(f, x, bndry->bx, bndry->y, 0, z); + extrapolateFurther(f, x, bndry->bx, bndry->y, 0, z); } } } @@ -121,7 +121,7 @@ void BoundaryOp::applyTemplate(T &f,BoutReal t) { // Need to set second and third guard cells, as may be used for interpolation or upwinding derivatives for (int i = 0; i < bndry->width; i++) { int x = bndry->x + i*bndry->bx; - extrapFurther(f, x, bndry->bx, bndry->y, 0, z); + extrapolateFurther(f, x, bndry->bx, bndry->y, 0, z); } } } @@ -144,7 +144,7 @@ void BoundaryOp::applyTemplate(T &f,BoutReal t) { // Need to set second guard cell, as may be used for interpolation or upwinding derivatives for(int i=1;iwidth;i++) { int y = bndry->y + i*bndry->by; - extrapFurther(f, bndry->x, 0, y, bndry->by, z); + extrapolateFurther(f, bndry->x, 0, y, bndry->by, z); } } } @@ -166,7 +166,7 @@ void BoundaryOp::applyTemplate(T &f,BoutReal t) { // Need to set second guard cell, as may be used for interpolation or upwinding derivatives for(int i=1;iwidth;i++) { int y = bndry->y + i*bndry->by; - extrapFurther(f, bndry->x, 0, y, bndry->by, z); + extrapolateFurther(f, bndry->x, 0, y, bndry->by, z); } } } @@ -188,7 +188,7 @@ void BoundaryOp::applyTemplate(T &f,BoutReal t) { // Need to set second guard cell, as may be used for interpolation or upwinding derivatives for(int i=0;iwidth;i++) { int y = bndry->y + i*bndry->by; - extrapFurther(f, bndry->x, 0, y, bndry->by, z); + extrapolateFurther(f, bndry->x, 0, y, bndry->by, z); } } } @@ -212,7 +212,7 @@ void BoundaryOp::applyTemplate(T &f,BoutReal t) { // Need to set second guard cell, as may be used for interpolation or upwinding derivatives for(int i=1;iwidth;i++) { int x = bndry->x + i*bndry->bx; - extrapFurther(f, x, bndry->bx, bndry->y, 0, z); + extrapolateFurther(f, x, bndry->bx, bndry->y, 0, z); } } } @@ -239,7 +239,7 @@ void BoundaryOp::applyTemplate(T &f,BoutReal t) { for (int i = 1; i < bndry->width; i++) { int x = bndry->x + i*bndry->bx; int y = bndry->y + i*bndry->by; - extrapFurther(f, x, bndry->bx, y, bndry->by, z); + extrapolateFurther(f, x, bndry->bx, y, bndry->by, z); } } } diff --git a/src/mesh/boundary_standard.cxx b/src/mesh/boundary_standard.cxx index 24815fa688..ba38937cdf 100644 --- a/src/mesh/boundary_standard.cxx +++ b/src/mesh/boundary_standard.cxx @@ -104,26 +104,26 @@ namespace { // 2nd order extrapolation to a point template - void extrap2nd(T &f, int x, int bx, int y, int by, int z) { + void extrapolate2nd(T &f, int x, int bx, int y, int by, int z) { f(x, y, z) = 2*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z); } // 3rd order extrapolation to a point template - void extrap3rd(T &f, int x, int bx, int y, int by, int z) { + void extrapolate3rd(T &f, int x, int bx, int y, int by, int z) { f(x, y, z) = 3.0*f(x - bx, y - by, z) - 3.0*f(x - 2*bx, y - 2*by, z) + f(x - 3*bx, y - 3*by, z); } // 4th order extrapolation to a point template - void extrap4th(T &f, int x, int bx, int y, int by, int z) { + void extrapolate4th(T &f, int x, int bx, int y, int by, int z) { f(x, y, z) = 4.0*f(x - bx, y - by, z) - 6.0*f(x - 2*bx, y - 2*by, z) + 4.0*f(x - 3*bx, y - 3*by, z) - f(x - 4*bx, y - 4*by, z); } // 5th order extrapolation to a point template - void extrap5th(T &f, int x, int bx, int y, int by, int z) { + void extrapolate5th(T &f, int x, int bx, int y, int by, int z) { f(x, y, z) = 5.0*f(x - bx, y - by, z) - 10.0*f(x - 2*bx, y - 2*by, z) + 10.0*f(x - 3*bx, y - 3*by, z) - 5.0*f(x - 4*bx, y - 4*by, z) + f(x - 5*bx, y - 5*by, z); @@ -437,11 +437,11 @@ void BoundaryDirichlet_O3::applyAtPointStaggered(Field3D &f, BoutReal val, int x f(x, y, z) = val; } -void BoundaryDirichlet_O3::extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) { - extrap3rd(f, x, bx, y, by, z); +void BoundaryDirichlet_O3::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { + extrapolate3rd(f, x, bx, y, by, z); } -void BoundaryDirichlet_O3::extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) { - extrap3rd(f, x, bx, y, by, z); +void BoundaryDirichlet_O3::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { + extrapolate3rd(f, x, bx, y, by, z); } /////////////////////////////////////////////////////////////// @@ -472,11 +472,11 @@ void BoundaryDirichlet_O4::applyAtPointStaggered(Field3D &f, BoutReal val, int x f(x, y, z) = val; } -void BoundaryDirichlet_O4::extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) { - extrap4th(f, x, bx, y, by, z); +void BoundaryDirichlet_O4::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { + extrapolate4th(f, x, bx, y, by, z); } -void BoundaryDirichlet_O4::extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) { - extrap4th(f, x, bx, y, by, z); +void BoundaryDirichlet_O4::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { + extrapolate4th(f, x, bx, y, by, z); } /////////////////////////////////////////////////////////////// @@ -569,15 +569,15 @@ void BoundaryDirichlet_O5::applyAtPointStaggered(Field3D &f, BoutReal val, int x f(x, y, z) = val; } -void BoundaryDirichlet_O5::extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) { +void BoundaryDirichlet_O5::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { // Changing this extrapolation to not depend on val, so just using grid point // values. JTO 16/10/2018 - extrap5th(f, x, bx, y, by, z); + extrapolate5th(f, x, bx, y, by, z); } -void BoundaryDirichlet_O5::extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) { +void BoundaryDirichlet_O5::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { // Changing this extrapolation to not depend on val, so just using grid point // values. Not sure if this is the correct order... JTO 16/10/2018 - extrap5th(f, x, bx, y, by, z); + extrapolate5th(f, x, bx, y, by, z); } @@ -774,11 +774,11 @@ void BoundaryNeumann_O4::applyAtPointStaggered(Field3D &f, BoutReal val, int x, + 4./3.*f(x - 3*bx, y - 3*by, z) - 1./4.*f(x - 4*bx, y - 4*by, z)); } -void BoundaryNeumann_O4::extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) { - extrap5th(f, x, bx, y, by, z); +void BoundaryNeumann_O4::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { + extrapolate5th(f, x, bx, y, by, z); } -void BoundaryNeumann_O4::extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) { - extrap5th(f, x, bx, y, by, z); +void BoundaryNeumann_O4::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { + extrapolate5th(f, x, bx, y, by, z); } /////////////////////////////////////////////////////////////// @@ -810,19 +810,19 @@ void BoundaryNeumann_4thOrder::applyAtPointStaggered(Field3D &UNUSED(f), BoutRea throw BoutException("BoundaryNeumann_4thOrder is not implemented for staggered grids."); } -void BoundaryNeumann_4thOrder::extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) { +void BoundaryNeumann_4thOrder::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { // Changing this extrapolation to not depend on val, so just using grid point // values. Previously was: // f(x+bx,y+by,z) = -24.*delta*val + 27.*f(x,y,z) - 27.*f(x-bx,y-by,z) + f(x-2*bx,y-2*by,z); // The f(x-4*bx,y-4*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 // - JTO 16/10/2018 - extrap5th(f, x, bx, y, by, z); + extrapolate5th(f, x, bx, y, by, z); } -void BoundaryNeumann_4thOrder::extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) { +void BoundaryNeumann_4thOrder::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { // Changing this extrapolation to not depend on val, so just using grid point // values. Previously was // f(x+bx,y+by,z) = -24.*delta*val + 27.*f(x,y,z) - 27.*f(x-bx,y-by,z) + f(x-2*bx,y-2*by,z); // The f(x-4*bx,y-4*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 // - JTO 16/10/2018 - extrap5th(f, x, bx, y, by, z); + extrapolate5th(f, x, bx, y, by, z); } /////////////////////////////////////////////////////////////// @@ -1325,17 +1325,17 @@ BoundaryOp* BoundaryFree_O2::clone(BoundaryRegion *region, const list &a } void BoundaryFree_O2::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { - extrap2nd(f, x, bx, y, by, z); + extrapolate2nd(f, x, bx, y, by, z); } void BoundaryFree_O2::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { - extrap2nd(f, x, bx, y, by, z); + extrapolate2nd(f, x, bx, y, by, z); } void BoundaryFree_O2::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { - extrap2nd(f, x, bx, y, by, z); + extrapolate2nd(f, x, bx, y, by, z); } void BoundaryFree_O2::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { - extrap2nd(f, x, bx, y, by, z); + extrapolate2nd(f, x, bx, y, by, z); } ////////////////////////////////// @@ -1351,24 +1351,24 @@ BoundaryOp* BoundaryFree_O3::clone(BoundaryRegion *region, const list &a } void BoundaryFree_O3::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { - extrap3rd(f, x, bx, y, by, z); + extrapolate3rd(f, x, bx, y, by, z); } void BoundaryFree_O3::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { - extrap3rd(f, x, bx, y, by, z); + extrapolate3rd(f, x, bx, y, by, z); } void BoundaryFree_O3::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { - extrap3rd(f, x, bx, y, by, z); + extrapolate3rd(f, x, bx, y, by, z); } void BoundaryFree_O3::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { - extrap3rd(f, x, bx, y, by, z); + extrapolate3rd(f, x, bx, y, by, z); } -void BoundaryFree_O3::extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) { - extrap3rd(f, x, bx, y, by, z); +void BoundaryFree_O3::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { + extrapolate3rd(f, x, bx, y, by, z); } -void BoundaryFree_O3::extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) { - extrap3rd(f, x, bx, y, by, z); +void BoundaryFree_O3::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { + extrapolate3rd(f, x, bx, y, by, z); } // Fourth order extrapolation: @@ -1382,24 +1382,24 @@ BoundaryOp* BoundaryFree_O4::clone(BoundaryRegion *region, const list &a } void BoundaryFree_O4::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { - extrap4th(f, x, bx, y, by, z); + extrapolate4th(f, x, bx, y, by, z); } void BoundaryFree_O4::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { - extrap4th(f, x, bx, y, by, z); + extrapolate4th(f, x, bx, y, by, z); } void BoundaryFree_O4::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { - extrap4th(f, x, bx, y, by, z); + extrapolate4th(f, x, bx, y, by, z); } void BoundaryFree_O4::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { - extrap4th(f, x, bx, y, by, z); + extrapolate4th(f, x, bx, y, by, z); } -void BoundaryFree_O4::extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) { - extrap4th(f, x, bx, y, by, z); +void BoundaryFree_O4::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { + extrapolate4th(f, x, bx, y, by, z); } -void BoundaryFree_O4::extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) { - extrap4th(f, x, bx, y, by, z); +void BoundaryFree_O4::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { + extrapolate4th(f, x, bx, y, by, z); } // Fifth order extrapolation: @@ -1413,24 +1413,24 @@ BoundaryOp* BoundaryFree_O5::clone(BoundaryRegion *region, const list &a } void BoundaryFree_O5::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { - extrap5th(f, x, bx, y, by, z); + extrapolate5th(f, x, bx, y, by, z); } void BoundaryFree_O5::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { - extrap5th(f, x, bx, y, by, z); + extrapolate5th(f, x, bx, y, by, z); } void BoundaryFree_O5::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { - extrap5th(f, x, bx, y, by, z); + extrapolate5th(f, x, bx, y, by, z); } void BoundaryFree_O5::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { - extrap5th(f, x, bx, y, by, z); + extrapolate5th(f, x, bx, y, by, z); } -void BoundaryFree_O5::extrapFurther(Field2D &f, int x, int bx, int y, int by, int z) { - extrap5th(f, x, bx, y, by, z); +void BoundaryFree_O5::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { + extrapolate5th(f, x, bx, y, by, z); } -void BoundaryFree_O5::extrapFurther(Field3D &f, int x, int bx, int y, int by, int z) { - extrap5th(f, x, bx, y, by, z); +void BoundaryFree_O5::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { + extrapolate5th(f, x, bx, y, by, z); } /////////////////////////////////////////////////////////////// From ed6ff040a2cb69c9c1bbe9672841b8a9bba82e09 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 29 Oct 2018 14:39:18 +0000 Subject: [PATCH 25/45] Make sure chains of conditionals use 'else if' e.g. bndry.bx can't be both <0 and >0, so use 'if(bndry->bx < 0) ... else if (bndry->bx > 0) ...'. Also make whitespace around conditionals more consistent. --- src/mesh/boundary_op.cxx | 37 ++++----- src/mesh/boundary_standard.cxx | 148 ++++++++++++++++----------------- 2 files changed, 89 insertions(+), 96 deletions(-) diff --git a/src/mesh/boundary_op.cxx b/src/mesh/boundary_op.cxx index 227c8fd3a8..44ecc4efd0 100644 --- a/src/mesh/boundary_op.cxx +++ b/src/mesh/boundary_op.cxx @@ -46,7 +46,7 @@ void BoundaryOp::applyTemplate(T &f,BoutReal t) { // Decide which generator to use std::shared_ptr fg = gen; - if(!fg) { + if (!fg) { fg = f.getBndryGenerator(bndry->location); } @@ -78,9 +78,10 @@ void BoundaryOp::applyTemplate(T &f,BoutReal t) { } } } - } if( loc == CELL_XLOW ) { + } + else if (loc == CELL_XLOW) { // field is shifted in X - if(bndry->bx > 0) { + if (bndry->bx > 0) { // Outer x boundary for(; !bndry->isDone(); bndry->next1d()) { BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) @@ -89,7 +90,7 @@ void BoundaryOp::applyTemplate(T &f,BoutReal t) { for(int z=0; zGlobalZ(z); - if(fg){ + if (fg) { val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); } applyAtPointStaggered(f, val, bndry->x, bndry->bx, bndry->y, 0, z, metric); @@ -101,8 +102,7 @@ void BoundaryOp::applyTemplate(T &f,BoutReal t) { } } } - } - if (bndry->bx < 0){ + } else if (bndry->bx < 0) { // Inner x boundary. Set one point inwards for(; !bndry->isDone(); bndry->next1d()) { @@ -112,7 +112,7 @@ void BoundaryOp::applyTemplate(T &f,BoutReal t) { for(int z=0; zGlobalZ(z); - if(fg){ + if (fg) { val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); } // Set one point inwards @@ -125,8 +125,7 @@ void BoundaryOp::applyTemplate(T &f,BoutReal t) { } } } - } - if(bndry->by !=0){ + } else if (bndry->by !=0) { // y boundaries for(; !bndry->isDone(); bndry->next1d()) { // x norm is shifted by half a grid point because it is staggered. @@ -136,7 +135,7 @@ void BoundaryOp::applyTemplate(T &f,BoutReal t) { for(int z=0; zGlobalZ(z); - if(fg){ + if (fg) { val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); } applyAtPoint(f, val, bndry->x, 0, bndry->y, bndry->by, z, metric); @@ -149,16 +148,16 @@ void BoundaryOp::applyTemplate(T &f,BoutReal t) { } } } - } else if( loc == CELL_YLOW ) { + } else if (loc == CELL_YLOW) { // Shifted in Y - if(bndry->by > 0) { + 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 z=0; zGlobalZ(z); - if(fg){ + if (fg) { val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); } applyAtPointStaggered(f, val, bndry->x, 0, bndry->y, bndry->by, z, metric); @@ -170,8 +169,7 @@ void BoundaryOp::applyTemplate(T &f,BoutReal t) { } } } - } - if(bndry->by < 0){ + } else if (bndry->by < 0) { // Lower y boundary. Set one point inwards for(; !bndry->isDone(); bndry->next1d()) { @@ -180,7 +178,7 @@ void BoundaryOp::applyTemplate(T &f,BoutReal t) { for(int z=0; zGlobalZ(z); - if(fg){ + if (fg) { val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); } applyAtPointStaggered(f, val, bndry->x, 0, bndry->y+1, bndry->by, z, metric); @@ -192,8 +190,7 @@ void BoundaryOp::applyTemplate(T &f,BoutReal t) { } } } - } - if(bndry->bx != 0){ + } else if (bndry->bx != 0) { // x boundaries for(; !bndry->isDone(); bndry->next1d()) { // x norm is located half way between first grid cell and guard cell. @@ -203,7 +200,7 @@ void BoundaryOp::applyTemplate(T &f,BoutReal t) { for(int z=0; zGlobalZ(z); - if(fg) { + if (fg) { val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); } @@ -217,7 +214,7 @@ void BoundaryOp::applyTemplate(T &f,BoutReal t) { } } } - } else if ( loc == CELL_ZLOW ){ + } else if (loc == CELL_ZLOW) { // Staggered in Z. Note there are no z-boundaries. for(; !bndry->isDone(); bndry->next1d()) { // Calculate the X and Y normalised values half-way between the guard cell and grid cell diff --git a/src/mesh/boundary_standard.cxx b/src/mesh/boundary_standard.cxx index ba38937cdf..d4fe7a59f0 100644 --- a/src/mesh/boundary_standard.cxx +++ b/src/mesh/boundary_standard.cxx @@ -48,14 +48,14 @@ namespace { //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; + if (localmesh->firstX()) ptsAvailLocal -= localmesh->xstart; + if (localmesh->lastX()) ptsAvailLocal -= localmesh->xstart; //Now decide if it's a local or global limit, prefer global if a tie - if(ptsAvailGlobal <= ptsAvailLocal){ + if (ptsAvailGlobal <= ptsAvailLocal) { ptsAvail = ptsAvailGlobal; gridType = "global"; - }else{ + } else { ptsAvail = ptsAvailLocal; gridType = "local"; } @@ -72,14 +72,14 @@ namespace { //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; + 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){ + if (ptsAvailGlobal <= ptsAvailLocal) { ptsAvail = ptsAvailGlobal; gridType = "global"; - }else{ + } else { ptsAvail = ptsAvailLocal; gridType = "local"; } @@ -94,7 +94,7 @@ namespace { } //Now check we have enough points and if not throw an exception - if(ptsAvail < ptsRequired){ + 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); } @@ -136,7 +136,7 @@ BoundaryOp* BoundaryDirichlet::clone(BoundaryRegion *region, const list verifyNumPoints(region, 1); std::shared_ptr newgen = nullptr; - if(!args.empty()) { + if (!args.empty()) { // First argument should be an expression newgen = FieldFactory::get()->parse(args.front()); } @@ -161,7 +161,7 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal t) { // Decide which generator to use std::shared_ptr fg = gen; - if(!fg) { + if (!fg) { fg = f.getBndryGenerator(bndry->location); } @@ -179,7 +179,7 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal t) { for(int zk=0; zkGlobalZ(zk); - if(fg){ + if (fg) { val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); } f(bndry->x,bndry->y,zk) = 2*val - f(bndry->x-bndry->bx, bndry->y-bndry->by, zk); @@ -222,16 +222,16 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal t) { ynorm = localmesh->GlobalY(yi); for(int zk=0; zkGlobalZ(zk); - if(fg) { + if (fg) { val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); } f(xi, yi, zk) = val; } } } - } else if( loc == CELL_XLOW ) { + } else if(loc == CELL_XLOW) { // Field is shifted in X - if(bndry->bx > 0) { + if (bndry->bx > 0) { // Outer x boundary for(; !bndry->isDone(); bndry->next1d()) { BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) @@ -240,7 +240,7 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal t) { for(int zk=0; zkGlobalZ(zk); - if(fg){ + if (fg) { val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); } f(bndry->x,bndry->y, zk) = val; @@ -254,8 +254,7 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal t) { } } } - } - if (bndry->bx < 0){ + } else if (bndry->bx < 0) { // Inner x boundary. Set one point inwards for(; !bndry->isDone(); bndry->next1d()) { @@ -265,7 +264,7 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal t) { for(int zk=0; zkGlobalZ(zk); - if(fg){ + if (fg) { val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); } f(bndry->x - bndry->bx,bndry->y, zk) = val; @@ -279,8 +278,7 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal t) { } } } - } - if(bndry->by !=0){ + } else if (bndry->by !=0) { // y boundaries for(; !bndry->isDone(); bndry->next1d()) { // x norm is shifted by half a grid point because it is staggered. @@ -290,7 +288,7 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal t) { for(int zk=0; zkGlobalZ(zk); - if(fg){ + if (fg) { val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); } f(bndry->x,bndry->y,zk) = 2*val - f(bndry->x-bndry->bx, bndry->y-bndry->by, zk); @@ -305,16 +303,16 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal t) { } } } - } else if( loc == CELL_YLOW ) { + } else if (loc == CELL_YLOW) { // Shifted in Y - if(bndry->by > 0) { + 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; zkGlobalZ(zk); - if(fg){ + if (fg) { val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); } f(bndry->x,bndry->y,zk) = val; @@ -328,8 +326,7 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal t) { } } } - } - if(bndry->by < 0){ + } else if (bndry->by < 0) { // Lower y boundary. Set one point inwards for(; !bndry->isDone(); bndry->next1d()) { @@ -338,7 +335,7 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal t) { for(int zk=0; zkGlobalZ(zk); - if(fg){ + if (fg) { val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); } f(bndry->x,bndry->y - bndry->by, zk) = val; @@ -352,8 +349,7 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal t) { } } } - } - if(bndry->bx != 0){ + } else if (bndry->bx != 0) { // x boundaries for(; !bndry->isDone(); bndry->next1d()) { // x norm is located half way between first grid cell and guard cell. @@ -363,7 +359,7 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal t) { for(int zk=0; zkGlobalZ(zk); - if(fg) { + if (fg) { val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); } @@ -392,7 +388,7 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal t) { for(int zk=0; zkgenerate should be periodic in z BoutReal znorm = 0.5*( localmesh->GlobalZ(zk) + localmesh->GlobalZ(zk - 1) ); // znorm is shifted by half a grid point because it is staggered - if(fg){ + if (fg) { val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); } f(bndry->x,bndry->y,zk) = 2*val - f(bndry->x-bndry->bx, bndry->y-bndry->by, zk); @@ -416,7 +412,7 @@ BoundaryOp* BoundaryDirichlet_O3::clone(BoundaryRegion *region, const list newgen = nullptr; - if(!args.empty()) { + if (!args.empty()) { // First argument should be an expression newgen = FieldFactory::get()->parse(args.front()); } @@ -451,7 +447,7 @@ BoundaryOp* BoundaryDirichlet_O4::clone(BoundaryRegion *region, const list newgen = nullptr; - if(!args.empty()) { + if (!args.empty()) { // First argument should be an expression newgen = FieldFactory::get()->parse(args.front()); } @@ -485,7 +481,7 @@ BoundaryOp* BoundaryDirichlet_smooth::clone(BoundaryRegion *region, const list newgen = nullptr; - if(!args.empty()) { + if (!args.empty()) { // First argument should be an expression newgen = FieldFactory::get()->parse(args.front()); } @@ -519,7 +515,7 @@ BoundaryOp* BoundaryDirichlet_2ndOrder::clone(BoundaryRegion *region, const list verifyNumPoints(region, 2); std::shared_ptr newgen = nullptr; - if(!args.empty()) { + if (!args.empty()) { // First argument should be an expression newgen = FieldFactory::get()->parse(args.front()); } @@ -548,7 +544,7 @@ BoundaryOp* BoundaryDirichlet_O5::clone(BoundaryRegion *region, const list newgen = nullptr; - if(!args.empty()) { + if (!args.empty()) { // First argument should be an expression newgen = FieldFactory::get()->parse(args.front()); } @@ -585,7 +581,7 @@ void BoundaryDirichlet_O5::extrapolateFurther(Field3D &f, int x, int bx, int y, BoundaryOp* BoundaryNeumann_NonOrthogonal::clone(BoundaryRegion *region, const list &args) { verifyNumPoints(region, 1); - if(!args.empty()) { + if (!args.empty()) { output << "WARNING: argument is set to BoundaryNeumann_NonOrthogonal\n"; // First argument should be a value val = stringToReal(args.front()); @@ -614,25 +610,25 @@ void BoundaryNeumann_NonOrthogonal::applyTemplate(T &f, BoutReal UNUSED(t)) { 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) { + if (bndry->bx != 0 && bndry->by == 0) { // x boundaries only BoutReal delta = bndry->bx*metric->dx(bndry->x, bndry->y); f(bndry->x, bndry->y, z) = f(bndry->x - bndry->bx, bndry->y, z) + delta/g11shift*(val - xshift); - if (bndry->width == 2){ + if (bndry->width == 2) { f(bndry->x + bndry->bx, bndry->y, z) = f(bndry->x - 2*bndry->bx, bndry->y, z) + 3.0*delta/g11shift*(val - xshift); } - } else if(bndry->by != 0 && bndry->bx == 0) { + } else if (bndry->by != 0 && bndry->bx == 0) { // y boundaries only // no need to shift this b/c we want parallel nuemann not theta BoutReal delta = bndry->by*metric->dy(bndry->x, bndry->y); f(bndry->x, bndry->y, z) = f(bndry->x, bndry->y - bndry->by, z) + delta*val; - if (bndry->width == 2){ + if (bndry->width == 2) { f(bndry->x, bndry->y + bndry->by, z) = f(bndry->x, bndry->y - 2*bndry->by, z) + 3.0*delta*val; } } else { // set corners to zero f(bndry->x, bndry->y, z) = 0.0; - if (bndry->width == 2){ + if (bndry->width == 2) { f(bndry->x + bndry->bx, bndry->y + bndry->by, z) = 0.0; } } @@ -648,7 +644,7 @@ BoundaryOp* BoundaryNeumann2::clone(BoundaryRegion *region, const list & verifyNumPoints(region, 2); std::shared_ptr newgen = nullptr; - if(!args.empty()) { + if (!args.empty()) { output << "WARNING: Ignoring arguments to BoundaryNeumann2\n"; } return new BoundaryNeumann2(region, newgen); @@ -676,7 +672,7 @@ BoundaryOp* BoundaryNeumann_2ndOrder::clone(BoundaryRegion *region, const list newgen = nullptr; - if(!args.empty()) { + if (!args.empty()) { // First argument should be an expression newgen = FieldFactory::get()->parse(args.front()); } @@ -707,7 +703,7 @@ BoundaryOp* BoundaryNeumann::clone(BoundaryRegion *region, const list &a verifyNumPoints(region, 1); std::shared_ptr newgen = nullptr; - if(!args.empty()) { + if (!args.empty()) { // First argument should be an expression newgen = FieldFactory::get()->parse(args.front()); } @@ -741,7 +737,7 @@ BoundaryOp* BoundaryNeumann_O4::clone(BoundaryRegion *region, const list verifyNumPoints(region, 4); std::shared_ptr newgen = nullptr; - if(!args.empty()) { + if (!args.empty()) { // First argument should be an expression newgen = FieldFactory::get()->parse(args.front()); } @@ -787,7 +783,7 @@ BoundaryOp* BoundaryNeumann_4thOrder::clone(BoundaryRegion *region, const list newgen = nullptr; - if(!args.empty()) { + if (!args.empty()) { // First argument should be an expression newgen = FieldFactory::get()->parse(args.front()); } @@ -831,7 +827,7 @@ BoundaryOp* BoundaryNeumannPar::clone(BoundaryRegion *region, const list verifyNumPoints(region, 1); std::shared_ptr newgen = nullptr; - if(!args.empty()) { + if (!args.empty()) { output << "WARNING: Ignoring arguments to BoundaryNeumannPar\n"; } return new BoundaryNeumannPar(region, newgen); @@ -861,21 +857,21 @@ BoundaryOp* BoundaryRobin::clone(BoundaryRegion *region, const list &arg list::const_iterator it = args.begin(); - if(it != args.end()) { + if (it != args.end()) { // First argument is 'a' a = stringToReal(*it); it++; - if(it != args.end()) { + if (it != args.end()) { // Second is 'b' b = stringToReal(*it); it++; - if(it != args.end()) { + if (it != args.end()) { // Third is 'g' g = stringToReal(*it); it++; - if(it != args.end()) { + if (it != args.end()) { output << "WARNING: BoundaryRobin takes maximum of 3 arguments. Ignoring extras\n"; } } @@ -887,7 +883,7 @@ BoundaryOp* BoundaryRobin::clone(BoundaryRegion *region, const list &arg template void BoundaryRobin::applyTemplate(T &f, BoutReal UNUSED(t)) { - if(fabs(bval) < 1.e-12) { + if (fabs(bval) < 1.e-12) { for(bndry->first(); !bndry->isDone(); bndry->next()) for(int z=0; zx, bndry->y, z) = gval / aval; @@ -908,7 +904,7 @@ BoundaryOp* BoundaryConstGradient::clone(BoundaryRegion *region, const list newgen = nullptr; - if(!args.empty()) { + if (!args.empty()) { output << "WARNING: Ignoring arguments to BoundaryConstGradient\n"; } return new BoundaryConstGradient(region, newgen); @@ -932,7 +928,7 @@ void BoundaryConstGradient::applyAtPointStaggered(Field3D &UNUSED(f), BoutReal U BoundaryOp* BoundaryZeroLaplace::clone(BoundaryRegion *region, const list &args) { verifyNumPoints(region, 2); - if(!args.empty()) { + if (!args.empty()) { output << "WARNING: Ignoring arguments to BoundaryZeroLaplace\n"; } return new BoundaryZeroLaplace(region); @@ -940,7 +936,7 @@ BoundaryOp* BoundaryZeroLaplace::clone(BoundaryRegion *region, const listlocation != BNDRY_XIN) && (bndry->location != BNDRY_XOUT)) { + if ((bndry->location != BNDRY_XIN) && (bndry->location != BNDRY_XOUT)) { // Can't apply this boundary condition to non-X boundaries throw BoutException("ERROR: Can't apply Zero Laplace condition to non-X boundaries\n"); } @@ -1109,14 +1105,14 @@ void BoundaryZeroLaplace2::apply(Field3D &f, BoutReal UNUSED(t)) { BoundaryOp* BoundaryConstLaplace::clone(BoundaryRegion *region, const list &args) { verifyNumPoints(region, 2); - if(!args.empty()) { + if (!args.empty()) { output << "WARNING: Ignoring arguments to BoundaryConstLaplace\n"; } return new BoundaryConstLaplace(region); } void BoundaryConstLaplace::apply(Field2D &f, BoutReal UNUSED(t)) { - if((bndry->location != BNDRY_XIN) && (bndry->location != BNDRY_XOUT)) { + if ((bndry->location != BNDRY_XIN) && (bndry->location != BNDRY_XOUT)) { // Can't apply this boundary condition to non-X boundaries throw BoutException("ERROR: Can't apply Zero Laplace condition to non-X boundaries\n"); } @@ -1134,7 +1130,7 @@ void BoundaryConstLaplace::apply(Field2D &f, BoutReal UNUSED(t)) { // Loop in X towards edge of domain do { laplace_tridag_coefs(x-bx, y, 0, la, lb, lc); - if(bx < 0) { // Lower X + if (bx < 0) { // Lower X f(x,y) = ((val - lb*f(x-bx,y) + lc*f(x-2*bx,y)) / la).real(); }else // Upper X f(x,y) = ((val - lb*f(x-bx,y) + la*f(x-2*bx,y)) / lc).real(); @@ -1146,7 +1142,7 @@ void BoundaryConstLaplace::apply(Field2D &f, BoutReal UNUSED(t)) { } void BoundaryConstLaplace::apply(Field3D &f, BoutReal UNUSED(t)) { - if((bndry->location != BNDRY_XIN) && (bndry->location != BNDRY_XOUT)) { + if ((bndry->location != BNDRY_XIN) && (bndry->location != BNDRY_XOUT)) { // Can't apply this boundary condition to non-X boundaries throw BoutException("ERROR: Can't apply Zero Laplace condition to non-X boundaries\n"); } @@ -1176,7 +1172,7 @@ void BoundaryConstLaplace::apply(Field3D &f, BoutReal UNUSED(t)) { for(int jz=0;jz<=ncz/2;jz++) { dcomplex la,lb,lc; laplace_tridag_coefs(x-2*bx, y, jz, la, lb, lc); - if(bx < 0) { // Inner X + if (bx < 0) { // Inner X c1[jz] = la*c0[jz] + lb*c1[jz] + lc*c2[jz]; }else { // Outer X c1[jz] = la*c2[jz] + lb*c1[jz] + lc*c0[jz]; @@ -1210,7 +1206,7 @@ void BoundaryConstLaplace::apply(Field3D &f, BoutReal UNUSED(t)) { /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryDivCurl::clone(BoundaryRegion *region, const list &args) { - if(!args.empty()) { + if (!args.empty()) { output << "WARNING: Ignoring arguments to BoundaryDivCurl\n"; } return new BoundaryDivCurl(region); @@ -1230,12 +1226,12 @@ void BoundaryDivCurl::apply(Vector3D &var) { int ncz = localmesh->LocalNz; - if(bndry->location != BNDRY_XOUT) { + if (bndry->location != BNDRY_XOUT) { throw BoutException("ERROR: DivCurl boundary only works for outer X currently\n"); } var.toCovariant(); - if(localmesh->xstart > 2) { + if (localmesh->xstart > 2) { throw BoutException("Error: Div = Curl = 0 boundary condition doesn't work for MXG > 2. Sorry\n"); } @@ -1251,7 +1247,7 @@ void BoundaryDivCurl::apply(Vector3D &var) { tmp = (var.x(jx-1,jy+1,jz) - var.x(jx-1,jy-1,jz)) / (metric->dy(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(localmesh->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; @@ -1260,7 +1256,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(localmesh->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) @@ -1279,7 +1275,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(localmesh->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); } @@ -1318,7 +1314,7 @@ void BoundaryFree::apply_ddt(Field3D &UNUSED(f)) { BoundaryOp* BoundaryFree_O2::clone(BoundaryRegion *region, const list &args){ verifyNumPoints(region, 2); - if(!args.empty()) { + if (!args.empty()) { output << "WARNING: Ignoring arguments to BoundaryFree_O2\n"; } return new BoundaryFree_O2(region) ; @@ -1344,7 +1340,7 @@ void BoundaryFree_O2::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), in BoundaryOp* BoundaryFree_O3::clone(BoundaryRegion *region, const list &args){ verifyNumPoints(region, 3); - if(!args.empty()) { + if (!args.empty()) { output << "WARNING: Ignoring arguments to BoundaryFree_O3\n"; } return new BoundaryFree_O3(region) ; @@ -1375,7 +1371,7 @@ void BoundaryFree_O3::extrapolateFurther(Field3D &f, int x, int bx, int y, int b BoundaryOp* BoundaryFree_O4::clone(BoundaryRegion *region, const list &args){ verifyNumPoints(region, 4); - if(!args.empty()) { + if (!args.empty()) { output << "WARNING: Ignoring arguments to BoundaryFree_O4\n"; } return new BoundaryFree_O4(region); @@ -1406,7 +1402,7 @@ void BoundaryFree_O4::extrapolateFurther(Field3D &f, int x, int bx, int y, int b BoundaryOp* BoundaryFree_O5::clone(BoundaryRegion *region, const list &args){ verifyNumPoints(region, 5); - if(!args.empty()) { + if (!args.empty()) { output << "WARNING: Ignoring arguments to BoundaryFree_O5\n"; } return new BoundaryFree_O5(region); @@ -1438,7 +1434,7 @@ void BoundaryFree_O5::extrapolateFurther(Field3D &f, int x, int bx, int y, int b BoundaryOp* BoundaryRelax::cloneMod(BoundaryOp *operation, const list &args) { BoundaryRelax* result = new BoundaryRelax(operation, r); - if(!args.empty()) { + if (!args.empty()) { // First argument should be the rate BoutReal val = stringToReal(args.front()); val = fabs(val); // Should always be positive @@ -1495,7 +1491,7 @@ void BoundaryRelax::apply_ddt(Field3D &f) { BoundaryOp* BoundaryWidth::cloneMod(BoundaryOp *operation, const list &args) { BoundaryWidth* result = new BoundaryWidth(operation, width); - if(args.empty()) { + if (args.empty()) { output << "WARNING: BoundaryWidth expected 1 argument\n"; }else { // First argument should be the rate @@ -1539,7 +1535,7 @@ void BoundaryWidth::apply_ddt(Field3D &f) { BoundaryOp* BoundaryToFieldAligned::cloneMod(BoundaryOp *operation, const list &args) { BoundaryToFieldAligned* result = new BoundaryToFieldAligned(operation); - if(!args.empty()) { + if (!args.empty()) { output << "WARNING: BoundaryToFieldAligned expected no argument\n"; //Shouldn't we throw ? } @@ -1586,7 +1582,7 @@ void BoundaryToFieldAligned::apply_ddt(Field3D &f) { BoundaryOp* BoundaryFromFieldAligned::cloneMod(BoundaryOp *operation, const list &args) { BoundaryFromFieldAligned* result = new BoundaryFromFieldAligned(operation); - if(!args.empty()) { + if (!args.empty()) { output << "WARNING: BoundaryFromFieldAligned expected no argument\n"; //Shouldn't we throw ? } From 205bc00c1ef0bfeef35c4338992d3cef00e73201 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 29 Oct 2018 15:22:40 +0000 Subject: [PATCH 26/45] Check bx and by are consistent in BoundaryRegion constructor I.e. one and only one of bx and by is non-zero. Also make bx and by 'const int' in BoundaryRegion and remove unused form of BoundaryRegion constructor that does not set bx or by. --- include/boundary_region.hxx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/include/boundary_region.hxx b/include/boundary_region.hxx index bf616293cc..b0bc214af5 100644 --- a/include/boundary_region.hxx +++ b/include/boundary_region.hxx @@ -4,6 +4,8 @@ class BoundaryRegion; #ifndef __BNDRY_REGION_H__ #define __BNDRY_REGION_H__ +#include + #include #include using std::string; @@ -24,14 +26,14 @@ enum BndryLoc {BNDRY_XIN=1, class BoundaryRegion { public: BoundaryRegion() = delete; - BoundaryRegion(std::string name, BndryLoc loc, Mesh *passmesh = nullptr) - : localmesh(passmesh ? passmesh : mesh), label(std::move(name)), location(loc) {} BoundaryRegion(std::string name, int xd, int yd, Mesh *passmesh = nullptr) - : bx(xd), by(yd), width(2), localmesh(passmesh ? passmesh : mesh), label(std::move(name)) {} + : bx(xd), by(yd), width(2), localmesh(passmesh ? passmesh : mesh), label(std::move(name)) { + ASSERT1(!(bx == 0 && by == 0) && !(bx != 0 && by != 0)); + } virtual ~BoundaryRegion() {} int x,y; ///< Indices of the point in the boundary - int bx, by; ///< Direction of the boundary [x+dx][y+dy] is going outwards + const int bx, by; ///< Direction of the boundary [x+dx][y+dy] is going outwards int width; ///< Width of the boundary From 5cb1be4ec3809778f7fbf9969bcc4475b5f41b4b Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 29 Oct 2018 16:08:03 +0000 Subject: [PATCH 27/45] Check boundary region exists in verifyNumPoints at standard CHECK level Was previously checked only for CHECK>2, but is not an expensive check. --- src/mesh/boundary_standard.cxx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/mesh/boundary_standard.cxx b/src/mesh/boundary_standard.cxx index d4fe7a59f0..a987f554df 100644 --- a/src/mesh/boundary_standard.cxx +++ b/src/mesh/boundary_standard.cxx @@ -86,11 +86,9 @@ namespace { break; } -#if CHECK > 2 //Only fail on Unrecognised boundary for extreme checking default : { throw BoutException("Unrecognised boundary region (%s) for verifyNumPoints.",region->location); } -#endif } //Now check we have enough points and if not throw an exception From f6feea4ecbf3fbaf0fa961649f559c01109dfe86 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 29 Oct 2018 16:56:31 +0000 Subject: [PATCH 28/45] Reduce code duplication in Boundary*::clone methods Use template helper functions to replace the bodies of most of the Boundary*::clone() methods. Two helper functions, one turning the first argument into an expression, and the other ignoring all arguments. --- src/mesh/boundary_standard.cxx | 191 ++++++++------------------------- 1 file changed, 45 insertions(+), 146 deletions(-) diff --git a/src/mesh/boundary_standard.cxx b/src/mesh/boundary_standard.cxx index a987f554df..ecb57fbb9b 100644 --- a/src/mesh/boundary_standard.cxx +++ b/src/mesh/boundary_standard.cxx @@ -126,19 +126,34 @@ namespace { + 10.0*f(x - 3*bx, y - 3*by, z) - 5.0*f(x - 4*bx, y - 4*by, z) + f(x - 5*bx, y - 5*by, z); } + + template + BoundaryOp* boundaryClone(BoundaryRegion* region, const list &args) { + verifyNumPoints(region, numpoints); + + std::shared_ptr newgen = nullptr; + if (!args.empty()) { + // First argument should be an expression + newgen = FieldFactory::get()->parse(args.front()); + } + return new T(region, newgen); + } + + template + BoundaryOp* boundaryCloneNoArguments(BoundaryRegion* region, const list &args) { + verifyNumPoints(region, numpoints); + + if (!args.empty()) { + output << "WARNING: Ignoring arguments to BoundaryOp for "<label<<" region\n"; + } + return new T(region); + } } /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryDirichlet::clone(BoundaryRegion *region, const list &args){ - verifyNumPoints(region, 1); - - std::shared_ptr newgen = nullptr; - if (!args.empty()) { - // First argument should be an expression - newgen = FieldFactory::get()->parse(args.front()); - } - return new BoundaryDirichlet(region, newgen); + return boundaryClone(region, args); } // Override apply(), using this private method to provide both Field2D and @@ -407,14 +422,7 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal t) { // New implementation, accurate to higher order BoundaryOp* BoundaryDirichlet_O3::clone(BoundaryRegion *region, const list &args){ - verifyNumPoints(region, 2); - - std::shared_ptr newgen = nullptr; - if (!args.empty()) { - // First argument should be an expression - newgen = FieldFactory::get()->parse(args.front()); - } - return new BoundaryDirichlet_O3(region, newgen); + return boundaryClone(region, args); } void BoundaryDirichlet_O3::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { @@ -442,14 +450,7 @@ void BoundaryDirichlet_O3::extrapolateFurther(Field3D &f, int x, int bx, int y, // Extrapolate to calculate boundary cell to 4th-order BoundaryOp* BoundaryDirichlet_O4::clone(BoundaryRegion *region, const list &args){ - verifyNumPoints(region, 3); - - std::shared_ptr newgen = nullptr; - if (!args.empty()) { - // First argument should be an expression - newgen = FieldFactory::get()->parse(args.front()); - } - return new BoundaryDirichlet_O4(region, newgen); + return boundaryClone(region, args); } void BoundaryDirichlet_O4::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { @@ -476,14 +477,7 @@ void BoundaryDirichlet_O4::extrapolateFurther(Field3D &f, int x, int bx, int y, /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryDirichlet_smooth::clone(BoundaryRegion *region, const list &args){ - verifyNumPoints(region, 2); - - std::shared_ptr newgen = nullptr; - if (!args.empty()) { - // First argument should be an expression - newgen = FieldFactory::get()->parse(args.front()); - } - return new BoundaryDirichlet_smooth(region, newgen); + return boundaryClone(region, args); } void BoundaryDirichlet_smooth::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { @@ -510,14 +504,7 @@ void BoundaryDirichlet_smooth::applyAtPointStaggered(Field3D &f, BoutReal val, i 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); - - std::shared_ptr newgen = nullptr; - if (!args.empty()) { - // First argument should be an expression - newgen = FieldFactory::get()->parse(args.front()); - } - return new BoundaryDirichlet_2ndOrder(region, newgen); + return boundaryClone(region, args); } // Set (at 2nd order) the value at the mid-point between the guard cell and the grid cell to be val @@ -539,14 +526,7 @@ void BoundaryDirichlet_2ndOrder::applyAtPointStaggered(Field3D &f, BoutReal val, /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryDirichlet_O5::clone(BoundaryRegion *region, const list &args) { - verifyNumPoints(region, 4); - - std::shared_ptr newgen = nullptr; - if (!args.empty()) { - // First argument should be an expression - newgen = FieldFactory::get()->parse(args.front()); - } - return new BoundaryDirichlet_O5(region, newgen); + return boundaryClone(region, args); } void BoundaryDirichlet_O5::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { @@ -639,13 +619,7 @@ void BoundaryNeumann_NonOrthogonal::applyTemplate(T &f, BoutReal UNUSED(t)) { 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); - - std::shared_ptr newgen = nullptr; - if (!args.empty()) { - output << "WARNING: Ignoring arguments to BoundaryNeumann2\n"; - } - return new BoundaryNeumann2(region, newgen); + return boundaryCloneNoArguments(region, args); } void BoundaryNeumann2::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { @@ -667,14 +641,7 @@ void BoundaryNeumann2::applyAtPointStaggered(Field3D &UNUSED(f), BoutReal UNUSED BoundaryOp* BoundaryNeumann_2ndOrder::clone(BoundaryRegion *region, const list &args) { output << "WARNING: Use of boundary condition \"neumann_2ndorder\" is deprecated!\n"; output << " Consider using \"neumann\" instead\n"; - verifyNumPoints(region, 1); - - std::shared_ptr newgen = nullptr; - if (!args.empty()) { - // First argument should be an expression - newgen = FieldFactory::get()->parse(args.front()); - } - return new BoundaryNeumann_2ndOrder(region, newgen); + return boundaryClone(region, args); } void BoundaryNeumann_2ndOrder::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { @@ -698,14 +665,7 @@ void BoundaryNeumann_2ndOrder::applyAtPointStaggered(Field3D &f, BoutReal val, i /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryNeumann::clone(BoundaryRegion *region, const list &args){ - verifyNumPoints(region, 1); - - std::shared_ptr newgen = nullptr; - if (!args.empty()) { - // First argument should be an expression - newgen = FieldFactory::get()->parse(args.front()); - } - return new BoundaryNeumann(region, newgen); + return boundaryClone(region, args); } void BoundaryNeumann::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { @@ -732,14 +692,7 @@ void BoundaryNeumann::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryNeumann_O4::clone(BoundaryRegion *region, const list &args){ - verifyNumPoints(region, 4); - - std::shared_ptr newgen = nullptr; - if (!args.empty()) { - // First argument should be an expression - newgen = FieldFactory::get()->parse(args.front()); - } - return new BoundaryNeumann_O4(region, newgen); + return boundaryClone(region, args); } void BoundaryNeumann_O4::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { @@ -778,14 +731,7 @@ void BoundaryNeumann_O4::extrapolateFurther(Field3D &f, int x, int bx, int y, in /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryNeumann_4thOrder::clone(BoundaryRegion *region, const list &args) { - verifyNumPoints(region, 4); - - std::shared_ptr newgen = nullptr; - if (!args.empty()) { - // First argument should be an expression - newgen = FieldFactory::get()->parse(args.front()); - } - return new BoundaryNeumann_4thOrder(region, newgen); + return boundaryClone(region, args); } void BoundaryNeumann_4thOrder::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { @@ -822,13 +768,7 @@ void BoundaryNeumann_4thOrder::extrapolateFurther(Field3D &f, int x, int bx, int /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryNeumannPar::clone(BoundaryRegion *region, const list &args) { - verifyNumPoints(region, 1); - - std::shared_ptr newgen = nullptr; - if (!args.empty()) { - output << "WARNING: Ignoring arguments to BoundaryNeumannPar\n"; - } - return new BoundaryNeumannPar(region, newgen); + return boundaryCloneNoArguments(region, args); } void BoundaryNeumannPar::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* metric) { @@ -899,13 +839,7 @@ void BoundaryRobin::applyTemplate(T &f, BoutReal UNUSED(t)) { /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryConstGradient::clone(BoundaryRegion *region, const list &args) { - verifyNumPoints(region, 2); - - std::shared_ptr newgen = nullptr; - if (!args.empty()) { - output << "WARNING: Ignoring arguments to BoundaryConstGradient\n"; - } - return new BoundaryConstGradient(region, newgen); + return boundaryCloneNoArguments(region, args); } void BoundaryConstGradient::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { @@ -925,11 +859,7 @@ void BoundaryConstGradient::applyAtPointStaggered(Field3D &UNUSED(f), BoutReal U /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryZeroLaplace::clone(BoundaryRegion *region, const list &args) { - verifyNumPoints(region, 2); - if (!args.empty()) { - output << "WARNING: Ignoring arguments to BoundaryZeroLaplace\n"; - } - return new BoundaryZeroLaplace(region); + return boundaryCloneNoArguments(region, args); } void BoundaryZeroLaplace::apply(Field2D &f, BoutReal UNUSED(t)) { @@ -1013,11 +943,7 @@ void BoundaryZeroLaplace::apply(Field3D &f, BoutReal UNUSED(t)) { BoundaryOp *BoundaryZeroLaplace2::clone(BoundaryRegion *region, const list &args) { - verifyNumPoints(region, 3); - if (!args.empty()) { - output << "WARNING: Ignoring arguments to BoundaryZeroLaplace2\n"; - } - return new BoundaryZeroLaplace2(region); + return boundaryCloneNoArguments(region, args); } void BoundaryZeroLaplace2::apply(Field2D &f, BoutReal UNUSED(t)) { @@ -1102,11 +1028,7 @@ void BoundaryZeroLaplace2::apply(Field3D &f, BoutReal UNUSED(t)) { /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryConstLaplace::clone(BoundaryRegion *region, const list &args) { - verifyNumPoints(region, 2); - if (!args.empty()) { - output << "WARNING: Ignoring arguments to BoundaryConstLaplace\n"; - } - return new BoundaryConstLaplace(region); + return boundaryCloneNoArguments(region, args); } void BoundaryConstLaplace::apply(Field2D &f, BoutReal UNUSED(t)) { @@ -1204,10 +1126,7 @@ void BoundaryConstLaplace::apply(Field3D &f, BoutReal UNUSED(t)) { /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryDivCurl::clone(BoundaryRegion *region, const list &args) { - if (!args.empty()) { - output << "WARNING: Ignoring arguments to BoundaryDivCurl\n"; - } - return new BoundaryDivCurl(region); + return boundaryCloneNoArguments(region, args); } void BoundaryDivCurl::apply(Vector2D &UNUSED(f)) { @@ -1282,8 +1201,8 @@ void BoundaryDivCurl::apply(Vector3D &var) { /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryFree::clone(BoundaryRegion *region, const list &UNUSED(args)) { - return new BoundaryFree(region); +BoundaryOp* BoundaryFree::clone(BoundaryRegion *region, const list &args) { + return boundaryCloneNoArguments(region, args); } void BoundaryFree::apply(Field2D &UNUSED(f), BoutReal UNUSED(t)) { @@ -1310,12 +1229,7 @@ void BoundaryFree::apply_ddt(Field3D &UNUSED(f)) { // 2nd order extrapolation: BoundaryOp* BoundaryFree_O2::clone(BoundaryRegion *region, const list &args){ - verifyNumPoints(region, 2); - - if (!args.empty()) { - output << "WARNING: Ignoring arguments to BoundaryFree_O2\n"; - } - return new BoundaryFree_O2(region) ; + return boundaryCloneNoArguments(region, args); } void BoundaryFree_O2::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { @@ -1336,12 +1250,7 @@ void BoundaryFree_O2::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), in // Third order extrapolation: ////////////////////////////////// BoundaryOp* BoundaryFree_O3::clone(BoundaryRegion *region, const list &args){ - verifyNumPoints(region, 3); - - if (!args.empty()) { - output << "WARNING: Ignoring arguments to BoundaryFree_O3\n"; - } - return new BoundaryFree_O3(region) ; + return boundaryCloneNoArguments(region, args); } void BoundaryFree_O3::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { @@ -1367,12 +1276,7 @@ void BoundaryFree_O3::extrapolateFurther(Field3D &f, int x, int bx, int y, int b // Fourth order extrapolation: BoundaryOp* BoundaryFree_O4::clone(BoundaryRegion *region, const list &args){ - verifyNumPoints(region, 4); - - if (!args.empty()) { - output << "WARNING: Ignoring arguments to BoundaryFree_O4\n"; - } - return new BoundaryFree_O4(region); + return boundaryCloneNoArguments(region, args); } void BoundaryFree_O4::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { @@ -1398,12 +1302,7 @@ void BoundaryFree_O4::extrapolateFurther(Field3D &f, int x, int bx, int y, int b // Fifth order extrapolation: BoundaryOp* BoundaryFree_O5::clone(BoundaryRegion *region, const list &args){ - verifyNumPoints(region, 5); - - if (!args.empty()) { - output << "WARNING: Ignoring arguments to BoundaryFree_O5\n"; - } - return new BoundaryFree_O5(region); + return boundaryCloneNoArguments(region, args); } void BoundaryFree_O5::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { From 24be7ee4e2fad58f14a7cd69d53b7f4384d53c3d Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 31 Oct 2018 14:16:43 +0000 Subject: [PATCH 29/45] Implement 'width' keyword for boundary conditions Also remove 2-argument 'clone' method, now all boundary conditions implement the 3-argument version, and throw an exception if they are passed keywords that they do not handle. --- include/boundary_op.hxx | 27 +++--- include/boundary_standard.hxx | 72 ++++++++++------ src/mesh/boundary_standard.cxx | 147 ++++++++++++++++++++++----------- 3 files changed, 155 insertions(+), 91 deletions(-) diff --git a/include/boundary_op.hxx b/include/boundary_op.hxx index 05f01a4dc7..5214376133 100644 --- a/include/boundary_op.hxx +++ b/include/boundary_op.hxx @@ -23,27 +23,19 @@ using std::list; class BoundaryOp { public: BoundaryOp() : bndry(nullptr), apply_to_ddt(false), gen(nullptr) {} - BoundaryOp(BoundaryRegion *region) - : bndry(region), apply_to_ddt(false), gen(nullptr) {} - BoundaryOp(BoundaryRegion *region, std::shared_ptr g) - : bndry(region), apply_to_ddt(false), gen(std::move(g)) {} + BoundaryOp(BoundaryRegion *region, int width_in = 0) + : bndry(region), apply_to_ddt(false), gen(nullptr), + width(width_in ? width_in : region->width) {} + BoundaryOp(BoundaryRegion *region, std::shared_ptr g, int width_in = 0) + : bndry(region), apply_to_ddt(false), gen(std::move(g)), + width(width_in ? width_in : region->width) {} virtual ~BoundaryOp() {} // Note: All methods must implement clone, except for modifiers (see below) - virtual BoundaryOp* clone(BoundaryRegion *UNUSED(region), const list &UNUSED(args)) { + virtual BoundaryOp *clone(BoundaryRegion *UNUSED(region), const list &UNUSED(args), + const std::map &UNUSED(keywords)) { throw BoutException("BoundaryOp::clone not implemented"); - } - - /// Clone using positional args and keywords - /// If not implemented, check if keywords are passed, then call two-argument version - virtual BoundaryOp *clone(BoundaryRegion *region, const list &args, - const std::map &keywords) { - if (!keywords.empty()) { - // Given keywords, but not using - throw BoutException("Keywords ignored in boundary : %s", keywords.begin()->first.c_str()); - } - - return clone(region, args); + return nullptr; } @@ -82,6 +74,7 @@ public: protected: std::shared_ptr gen; // Generator + const int width; // boundary width, stored in case we change it from the default // Apply boundary condition at a point virtual void applyAtPoint(Field2D &UNUSED(f), BoutReal UNUSED(val), int diff --git a/include/boundary_standard.hxx b/include/boundary_standard.hxx index 4f582bf9c4..e4564211f4 100644 --- a/include/boundary_standard.hxx +++ b/include/boundary_standard.hxx @@ -14,7 +14,8 @@ class BoundaryDirichlet : public BoundaryOp { public: using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; using BoundaryOp::apply; void apply(Field2D &f,BoutReal t = 0.) override { @@ -35,7 +36,8 @@ BoutReal default_func(BoutReal t, int x, int y, int z); class BoundaryDirichlet_O3 : public BoundaryOp { public: using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; @@ -49,7 +51,8 @@ class BoundaryDirichlet_O3 : public BoundaryOp { class BoundaryDirichlet_O4 : public BoundaryOp { public: using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; @@ -63,7 +66,8 @@ class BoundaryDirichlet_O4 : public BoundaryOp { class BoundaryDirichlet_smooth : public BoundaryOp { public: using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; @@ -75,7 +79,8 @@ class BoundaryDirichlet_smooth : public BoundaryOp { class BoundaryDirichlet_2ndOrder : public BoundaryOp { public: using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; @@ -87,7 +92,8 @@ class BoundaryDirichlet_2ndOrder : public BoundaryOp { class BoundaryDirichlet_O5 : public BoundaryOp { public: using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; @@ -103,7 +109,8 @@ class BoundaryNeumann_NonOrthogonal : public BoundaryOp { BoundaryNeumann_NonOrthogonal(): val(0.) {} BoundaryNeumann_NonOrthogonal(BoutReal setval ): val(setval) {} BoundaryNeumann_NonOrthogonal(BoundaryRegion *region, BoutReal setval=0.):BoundaryOp(region),val(setval) { } - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; using BoundaryOp::apply; void apply(Field2D &f, BoutReal t = 0.) override { @@ -123,7 +130,8 @@ class BoundaryNeumann_NonOrthogonal : public BoundaryOp { class BoundaryNeumann2 : public BoundaryOp { public: using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; @@ -135,7 +143,8 @@ class BoundaryNeumann2 : public BoundaryOp { class BoundaryNeumann_2ndOrder : public BoundaryOp { public: using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; @@ -147,7 +156,8 @@ class BoundaryNeumann_2ndOrder : public BoundaryOp { class BoundaryNeumann : public BoundaryOp { public: using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; @@ -159,7 +169,8 @@ class BoundaryNeumann : public BoundaryOp { class BoundaryNeumann_O4 : public BoundaryOp { public: using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; @@ -173,7 +184,8 @@ class BoundaryNeumann_O4 : public BoundaryOp { class BoundaryNeumann_4thOrder : public BoundaryOp { public: using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; @@ -188,7 +200,8 @@ class BoundaryNeumann_4thOrder : public BoundaryOp { class BoundaryNeumannPar : public BoundaryOp { public: using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; @@ -202,7 +215,8 @@ class BoundaryRobin : public BoundaryOp { BoundaryRobin() : aval(0.), bval(0.), gval(0.) {} BoundaryRobin(BoundaryRegion *region, BoutReal a, BoutReal b, BoutReal g) : BoundaryOp(region), aval(a), bval(b), gval(g) { } - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; using BoundaryOp::apply; void apply(Field2D &f, BoutReal t = 0.) override { @@ -222,7 +236,8 @@ private: class BoundaryConstGradient : public BoundaryOp { public: using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; @@ -235,7 +250,8 @@ class BoundaryZeroLaplace : public BoundaryOp { public: BoundaryZeroLaplace() {} BoundaryZeroLaplace(BoundaryRegion *region):BoundaryOp(region) { } - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; using BoundaryOp::apply; void apply(Field2D &f, BoutReal UNUSED(t)) override; @@ -247,7 +263,8 @@ class BoundaryZeroLaplace2 : public BoundaryOp { public: BoundaryZeroLaplace2() {} BoundaryZeroLaplace2(BoundaryRegion *region):BoundaryOp(region) { } - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; using BoundaryOp::apply; void apply(Field2D &f, BoutReal t) override; @@ -259,7 +276,8 @@ class BoundaryConstLaplace : public BoundaryOp { public: BoundaryConstLaplace() {} BoundaryConstLaplace(BoundaryRegion *region):BoundaryOp(region) { } - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; using BoundaryOp::apply; void apply(Field2D &f, BoutReal t) override; @@ -271,7 +289,8 @@ class BoundaryDivCurl : public BoundaryOp { public: BoundaryDivCurl() {} BoundaryDivCurl(BoundaryRegion *region):BoundaryOp(region) { } - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; using BoundaryOp::apply; void apply(Field2D &UNUSED(f), BoutReal UNUSED(t)) override { throw BoutException("ERROR: DivCurl boundary only for vectors"); } @@ -284,7 +303,8 @@ class BoundaryDivCurl : public BoundaryOp { class BoundaryFree : public BoundaryOp { public: using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; using BoundaryOp::apply; void apply(Field2D &f, BoutReal UNUSED(t)) override; @@ -302,7 +322,8 @@ class BoundaryFree : public BoundaryOp { class BoundaryFree_O2 : public BoundaryOp { public: using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; @@ -313,7 +334,8 @@ public: class BoundaryFree_O3 : public BoundaryOp { public: using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; @@ -327,7 +349,8 @@ public: class BoundaryFree_O4 : public BoundaryOp { public: using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; @@ -340,7 +363,8 @@ public: class BoundaryFree_O5 : public BoundaryOp { public: using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; diff --git a/src/mesh/boundary_standard.cxx b/src/mesh/boundary_standard.cxx index ecb57fbb9b..4cdd5361e0 100644 --- a/src/mesh/boundary_standard.cxx +++ b/src/mesh/boundary_standard.cxx @@ -128,7 +128,8 @@ namespace { } template - BoundaryOp* boundaryClone(BoundaryRegion* region, const list &args) { + BoundaryOp* boundaryClone(BoundaryRegion* region, const list &args, + const std::map &keywords) { verifyNumPoints(region, numpoints); std::shared_ptr newgen = nullptr; @@ -136,24 +137,39 @@ namespace { // First argument should be an expression newgen = FieldFactory::get()->parse(args.front()); } - return new T(region, newgen); + int width = region->width; + for (const auto &it : keywords) { + if (it.first == "width") { + width = stringToInt(it.second); + } else { + throw BoutException("Unrecognized boundary condition keyword %s for %s boundary", it.first.c_str(), region->label.c_str()); + } + } + return new T(region, newgen, width); } template - BoundaryOp* boundaryCloneNoArguments(BoundaryRegion* region, const list &args) { + BoundaryOp* boundaryCloneNoArguments(BoundaryRegion* region, const list &args, + const std::map &keywords) { verifyNumPoints(region, numpoints); if (!args.empty()) { output << "WARNING: Ignoring arguments to BoundaryOp for "<label<<" region\n"; } + if (!keywords.empty()) { + // Given keywords, but not using + throw BoutException("Keywords ignored in boundary : %s", keywords.begin()->first.c_str()); + } + return new T(region); } } /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryDirichlet::clone(BoundaryRegion *region, const list &args){ - return boundaryClone(region, args); +BoundaryOp* BoundaryDirichlet::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { + return boundaryClone(region, args, keywords); } // Override apply(), using this private method to provide both Field2D and @@ -421,8 +437,9 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal t) { /////////////////////////////////////////////////////////////// // New implementation, accurate to higher order -BoundaryOp* BoundaryDirichlet_O3::clone(BoundaryRegion *region, const list &args){ - return boundaryClone(region, args); +BoundaryOp* BoundaryDirichlet_O3::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { + return boundaryClone(region, args, keywords); } void BoundaryDirichlet_O3::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { @@ -449,8 +466,9 @@ void BoundaryDirichlet_O3::extrapolateFurther(Field3D &f, int x, int bx, int y, /////////////////////////////////////////////////////////////// // Extrapolate to calculate boundary cell to 4th-order -BoundaryOp* BoundaryDirichlet_O4::clone(BoundaryRegion *region, const list &args){ - return boundaryClone(region, args); +BoundaryOp* BoundaryDirichlet_O4::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { + return boundaryClone(region, args, keywords); } void BoundaryDirichlet_O4::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { @@ -476,8 +494,9 @@ void BoundaryDirichlet_O4::extrapolateFurther(Field3D &f, int x, int bx, int y, /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryDirichlet_smooth::clone(BoundaryRegion *region, const list &args){ - return boundaryClone(region, args); +BoundaryOp* BoundaryDirichlet_smooth::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { + return boundaryClone(region, args, keywords); } void BoundaryDirichlet_smooth::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { @@ -501,10 +520,11 @@ void BoundaryDirichlet_smooth::applyAtPointStaggered(Field3D &f, BoutReal val, i } /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryDirichlet_2ndOrder::clone(BoundaryRegion *region, const list &args) { +BoundaryOp* BoundaryDirichlet_2ndOrder::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { output << "WARNING: Use of boundary condition \"dirichlet_2ndorder\" is deprecated!\n"; output << " Consider using \"dirichlet\" instead\n"; - return boundaryClone(region, args); + return boundaryClone(region, args, keywords); } // Set (at 2nd order) the value at the mid-point between the guard cell and the grid cell to be val @@ -525,8 +545,9 @@ void BoundaryDirichlet_2ndOrder::applyAtPointStaggered(Field3D &f, BoutReal val, /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryDirichlet_O5::clone(BoundaryRegion *region, const list &args) { - return boundaryClone(region, args); +BoundaryOp* BoundaryDirichlet_O5::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { + return boundaryClone(region, args, keywords); } void BoundaryDirichlet_O5::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { @@ -557,7 +578,8 @@ void BoundaryDirichlet_O5::extrapolateFurther(Field3D &f, int x, int bx, int y, /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryNeumann_NonOrthogonal::clone(BoundaryRegion *region, const list &args) { +BoundaryOp* BoundaryNeumann_NonOrthogonal::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { verifyNumPoints(region, 1); if (!args.empty()) { output << "WARNING: argument is set to BoundaryNeumann_NonOrthogonal\n"; @@ -565,6 +587,10 @@ BoundaryOp* BoundaryNeumann_NonOrthogonal::clone(BoundaryRegion *region, const l val = stringToReal(args.front()); return new BoundaryNeumann_NonOrthogonal(region, val); } + if (!keywords.empty()) { + // Given keywords, but not using + throw BoutException("Keywords ignored in boundary : %s", keywords.begin()->first.c_str()); + } return new BoundaryNeumann_NonOrthogonal(region); } @@ -616,10 +642,11 @@ void BoundaryNeumann_NonOrthogonal::applyTemplate(T &f, BoutReal UNUSED(t)) { /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryNeumann2::clone(BoundaryRegion *region, const list &args) { +BoundaryOp* BoundaryNeumann2::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { output << "WARNING: Use of boundary condition \"neumann2\" is deprecated!\n"; output << " Consider using \"neumann\" instead\n"; - return boundaryCloneNoArguments(region, args); + return boundaryCloneNoArguments(region, args, keywords); } void BoundaryNeumann2::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { @@ -638,10 +665,11 @@ void BoundaryNeumann2::applyAtPointStaggered(Field3D &UNUSED(f), BoutReal UNUSED /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryNeumann_2ndOrder::clone(BoundaryRegion *region, const list &args) { +BoundaryOp* BoundaryNeumann_2ndOrder::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { output << "WARNING: Use of boundary condition \"neumann_2ndorder\" is deprecated!\n"; output << " Consider using \"neumann\" instead\n"; - return boundaryClone(region, args); + return boundaryClone(region, args, keywords); } void BoundaryNeumann_2ndOrder::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { @@ -664,8 +692,9 @@ void BoundaryNeumann_2ndOrder::applyAtPointStaggered(Field3D &f, BoutReal val, i /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryNeumann::clone(BoundaryRegion *region, const list &args){ - return boundaryClone(region, args); +BoundaryOp* BoundaryNeumann::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { + return boundaryClone(region, args, keywords); } void BoundaryNeumann::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { @@ -691,8 +720,9 @@ void BoundaryNeumann::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryNeumann_O4::clone(BoundaryRegion *region, const list &args){ - return boundaryClone(region, args); +BoundaryOp* BoundaryNeumann_O4::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { + return boundaryClone(region, args, keywords); } void BoundaryNeumann_O4::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { @@ -730,8 +760,9 @@ void BoundaryNeumann_O4::extrapolateFurther(Field3D &f, int x, int bx, int y, in /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryNeumann_4thOrder::clone(BoundaryRegion *region, const list &args) { - return boundaryClone(region, args); +BoundaryOp* BoundaryNeumann_4thOrder::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { + return boundaryClone(region, args, keywords); } void BoundaryNeumann_4thOrder::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { @@ -767,8 +798,9 @@ void BoundaryNeumann_4thOrder::extrapolateFurther(Field3D &f, int x, int bx, int /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryNeumannPar::clone(BoundaryRegion *region, const list &args) { - return boundaryCloneNoArguments(region, args); +BoundaryOp* BoundaryNeumannPar::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { + return boundaryCloneNoArguments(region, args, keywords); } void BoundaryNeumannPar::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* metric) { @@ -789,12 +821,18 @@ void BoundaryNeumannPar::applyAtPointStaggered(Field3D &UNUSED(f), BoutReal UNUS /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryRobin::clone(BoundaryRegion *region, const list &args) { +BoundaryOp* BoundaryRobin::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { verifyNumPoints(region, 1); BoutReal a = 0.5, b = 1.0, g = 0.; list::const_iterator it = args.begin(); + if (!keywords.empty()) { + // Given keywords, but not using + throw BoutException("Keywords ignored in boundary : %s", keywords.begin()->first.c_str()); + } + if (it != args.end()) { // First argument is 'a' a = stringToReal(*it); @@ -838,8 +876,9 @@ void BoundaryRobin::applyTemplate(T &f, BoutReal UNUSED(t)) { /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryConstGradient::clone(BoundaryRegion *region, const list &args) { - return boundaryCloneNoArguments(region, args); +BoundaryOp* BoundaryConstGradient::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { + return boundaryCloneNoArguments(region, args, keywords); } void BoundaryConstGradient::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { @@ -858,8 +897,9 @@ void BoundaryConstGradient::applyAtPointStaggered(Field3D &UNUSED(f), BoutReal U /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryZeroLaplace::clone(BoundaryRegion *region, const list &args) { - return boundaryCloneNoArguments(region, args); +BoundaryOp* BoundaryZeroLaplace::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { + return boundaryCloneNoArguments(region, args, keywords); } void BoundaryZeroLaplace::apply(Field2D &f, BoutReal UNUSED(t)) { @@ -941,9 +981,9 @@ void BoundaryZeroLaplace::apply(Field3D &f, BoutReal UNUSED(t)) { /////////////////////////////////////////////////////////////// -BoundaryOp *BoundaryZeroLaplace2::clone(BoundaryRegion *region, - const list &args) { - return boundaryCloneNoArguments(region, args); +BoundaryOp *BoundaryZeroLaplace2::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { + return boundaryCloneNoArguments(region, args, keywords); } void BoundaryZeroLaplace2::apply(Field2D &f, BoutReal UNUSED(t)) { @@ -1027,8 +1067,9 @@ void BoundaryZeroLaplace2::apply(Field3D &f, BoutReal UNUSED(t)) { /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryConstLaplace::clone(BoundaryRegion *region, const list &args) { - return boundaryCloneNoArguments(region, args); +BoundaryOp* BoundaryConstLaplace::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { + return boundaryCloneNoArguments(region, args, keywords); } void BoundaryConstLaplace::apply(Field2D &f, BoutReal UNUSED(t)) { @@ -1125,8 +1166,9 @@ void BoundaryConstLaplace::apply(Field3D &f, BoutReal UNUSED(t)) { /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryDivCurl::clone(BoundaryRegion *region, const list &args) { - return boundaryCloneNoArguments(region, args); +BoundaryOp* BoundaryDivCurl::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { + return boundaryCloneNoArguments(region, args, keywords); } void BoundaryDivCurl::apply(Vector2D &UNUSED(f)) { @@ -1201,8 +1243,9 @@ void BoundaryDivCurl::apply(Vector3D &var) { /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryFree::clone(BoundaryRegion *region, const list &args) { - return boundaryCloneNoArguments(region, args); +BoundaryOp* BoundaryFree::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { + return boundaryCloneNoArguments(region, args, keywords); } void BoundaryFree::apply(Field2D &UNUSED(f), BoutReal UNUSED(t)) { @@ -1228,8 +1271,9 @@ void BoundaryFree::apply_ddt(Field3D &UNUSED(f)) { // 2nd order extrapolation: -BoundaryOp* BoundaryFree_O2::clone(BoundaryRegion *region, const list &args){ - return boundaryCloneNoArguments(region, args); +BoundaryOp* BoundaryFree_O2::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { + return boundaryCloneNoArguments(region, args, keywords); } void BoundaryFree_O2::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { @@ -1249,8 +1293,9 @@ void BoundaryFree_O2::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), in ////////////////////////////////// // Third order extrapolation: ////////////////////////////////// -BoundaryOp* BoundaryFree_O3::clone(BoundaryRegion *region, const list &args){ - return boundaryCloneNoArguments(region, args); +BoundaryOp* BoundaryFree_O3::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { + return boundaryCloneNoArguments(region, args, keywords); } void BoundaryFree_O3::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { @@ -1275,8 +1320,9 @@ void BoundaryFree_O3::extrapolateFurther(Field3D &f, int x, int bx, int y, int b } // Fourth order extrapolation: -BoundaryOp* BoundaryFree_O4::clone(BoundaryRegion *region, const list &args){ - return boundaryCloneNoArguments(region, args); +BoundaryOp* BoundaryFree_O4::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { + return boundaryCloneNoArguments(region, args, keywords); } void BoundaryFree_O4::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { @@ -1301,8 +1347,9 @@ void BoundaryFree_O4::extrapolateFurther(Field3D &f, int x, int bx, int y, int b } // Fifth order extrapolation: -BoundaryOp* BoundaryFree_O5::clone(BoundaryRegion *region, const list &args){ - return boundaryCloneNoArguments(region, args); +BoundaryOp* BoundaryFree_O5::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { + return boundaryCloneNoArguments(region, args, keywords); } void BoundaryFree_O5::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { From d5c61d605f44229fb1c39dc5f9cd7d070569e2d9 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 31 Oct 2018 14:20:02 +0000 Subject: [PATCH 30/45] Make BoundaryOp and BoundaryRegion members const, deprecate BoundaryWidth Make several member variables const: apply_to_ddt of BoundaryOp and width and label of BoundaryRegion. The (probably never used) functionality of the BoundaryWidth modifier has been replaced with 'width' keyword to boundary conditions. The BoundaryWidth modifier needs to keep changing BoundaryRegion::width, which we are making const, so can no longer be used. Trying to use a BoundaryWidth modifier now throws an exception with an instruction to use the 'width' keyword instead. --- include/boundary_op.hxx | 14 ++++++----- include/boundary_region.hxx | 13 +++++----- include/boundary_standard.hxx | 19 ++++++++------- src/mesh/boundary_region.cxx | 26 ++++++++++---------- src/mesh/boundary_standard.cxx | 44 ---------------------------------- 5 files changed, 39 insertions(+), 77 deletions(-) diff --git a/include/boundary_op.hxx b/include/boundary_op.hxx index 5214376133..bf61c453ae 100644 --- a/include/boundary_op.hxx +++ b/include/boundary_op.hxx @@ -22,9 +22,10 @@ using std::list; /// An operation on a boundary class BoundaryOp { public: - BoundaryOp() : bndry(nullptr), apply_to_ddt(false), gen(nullptr) {} - BoundaryOp(BoundaryRegion *region, int width_in = 0) - : bndry(region), apply_to_ddt(false), gen(nullptr), + BoundaryOp(bool apply_ddt = false) : bndry(nullptr), apply_to_ddt(apply_ddt), + gen(nullptr), width(0) {} + BoundaryOp(BoundaryRegion *region, int width_in = 0, bool apply_ddt = false) + : bndry(region), apply_to_ddt(apply_ddt), gen(nullptr), width(width_in ? width_in : region->width) {} BoundaryOp(BoundaryRegion *region, std::shared_ptr g, int width_in = 0) : bndry(region), apply_to_ddt(false), gen(std::move(g)), @@ -70,7 +71,7 @@ public: } BoundaryRegion *bndry; - bool apply_to_ddt; // True if this boundary condition should be applied on the time derivatives, false if it should be applied to the field values + const bool apply_to_ddt; // True if this boundary condition should be applied on the time derivatives, false if it should be applied to the field values protected: std::shared_ptr gen; // Generator @@ -119,8 +120,9 @@ private: class BoundaryModifier : public BoundaryOp { public: - BoundaryModifier() : op(nullptr) {} - BoundaryModifier(BoundaryOp *operation) : BoundaryOp(operation->bndry), op(operation) {} + BoundaryModifier(bool apply_ddt = false) : BoundaryOp(apply_ddt), op(nullptr) {} + BoundaryModifier(BoundaryOp *operation, bool apply_ddt = false) + : BoundaryOp(operation->bndry, 0, apply_ddt), op(operation) {} virtual BoundaryOp* cloneMod(BoundaryOp *op, const list &args) = 0; virtual BoundaryOpPar* cloneMod(BoundaryOpPar *UNUSED(op), const list &UNUSED(args)) { throw BoutException("BoundaryModifier should not be called on a BoundaryOpPar."); diff --git a/include/boundary_region.hxx b/include/boundary_region.hxx index b0bc214af5..4771671c9e 100644 --- a/include/boundary_region.hxx +++ b/include/boundary_region.hxx @@ -26,16 +26,17 @@ enum BndryLoc {BNDRY_XIN=1, class BoundaryRegion { public: BoundaryRegion() = delete; - BoundaryRegion(std::string name, int xd, int yd, Mesh *passmesh = nullptr) - : bx(xd), by(yd), width(2), localmesh(passmesh ? passmesh : mesh), label(std::move(name)) { - ASSERT1(!(bx == 0 && by == 0) && !(bx != 0 && by != 0)); - } + BoundaryRegion(std::string name, int xd, int yd, BndryLoc loc, int wid, Mesh *passmesh = nullptr) + : bx(xd), by(yd), width(wid), localmesh(passmesh ? passmesh : mesh), + label(std::move(name)), location(loc) { + ASSERT1(!(bx == 0 && by == 0) && !(bx != 0 && by != 0)); + } virtual ~BoundaryRegion() {} int x,y; ///< Indices of the point in the boundary const int bx, by; ///< Direction of the boundary [x+dx][y+dy] is going outwards - int width; ///< Width of the boundary + const int width; ///< Width of the boundary virtual void next1d() = 0; ///< Loop over the innermost elements virtual void nextX() = 0; ///< Just loop over X @@ -43,7 +44,7 @@ public: Mesh* localmesh; ///< Mesh does this boundary region belongs to - string label; ///< Label for this boundary region + const string label; ///< Label for this boundary region BndryLoc location; ///< Which side of the domain is it on? diff --git a/include/boundary_standard.hxx b/include/boundary_standard.hxx index e4564211f4..004fbf1995 100644 --- a/include/boundary_standard.hxx +++ b/include/boundary_standard.hxx @@ -379,8 +379,8 @@ public: /// Convert a boundary condition to a relaxing one class BoundaryRelax : public BoundaryModifier { public: - BoundaryRelax() : r(10.) {apply_to_ddt = true;} // Set default rate - BoundaryRelax(BoundaryOp *operation, BoutReal rate) : BoundaryModifier(operation) {r = fabs(rate); apply_to_ddt = true;} + BoundaryRelax() : BoundaryModifier(true), r(10.) {} // Set default rate + BoundaryRelax(BoundaryOp *operation, BoutReal rate) : BoundaryModifier(operation, true) { r = fabs(rate); } BoundaryOp* cloneMod(BoundaryOp *op, const list &args) override; using BoundaryModifier::apply; @@ -399,15 +399,16 @@ class BoundaryWidth : public BoundaryModifier { public: BoundaryWidth() : width(2) {} BoundaryWidth(BoundaryOp *operation, int wid) : BoundaryModifier(operation), width(wid) {} - BoundaryOp* cloneMod(BoundaryOp *op, const list &args) override; + BoundaryOp* cloneMod(BoundaryOp *UNUSED(op), const list &UNUSED(args)) override { + throw BoutException("WARNING: BoundaryWidth modifier is deprecated, use 'width' keyword to boundary conditions instead"); + return new BoundaryWidth(nullptr, 0); + } - using BoundaryModifier::apply; - void apply(Field2D &f, BoutReal t) override; - void apply(Field3D &f, BoutReal t) override; + void apply(Field2D &UNUSED(f), BoutReal UNUSED(t)) override {}; + void apply(Field3D &UNUSED(f), BoutReal UNUSED(t)) override {}; - using BoundaryModifier::apply_ddt; - void apply_ddt(Field2D &f) override; - void apply_ddt(Field3D &f) override; + void apply_ddt(Field2D &UNUSED(f)) override {}; + void apply_ddt(Field3D &UNUSED(f)) override {}; private: int width; }; diff --git a/src/mesh/boundary_region.cxx b/src/mesh/boundary_region.cxx index 0ddd615e1d..ef314751e2 100644 --- a/src/mesh/boundary_region.cxx +++ b/src/mesh/boundary_region.cxx @@ -4,10 +4,10 @@ #include BoundaryRegionXIn::BoundaryRegionXIn(std::string name, int ymin, int ymax, Mesh* passmesh) - : BoundaryRegion(name, -1, 0, passmesh), ys(ymin), ye(ymax) + : BoundaryRegion(name, -1, 0, BNDRY_XIN, + (passmesh == nullptr ? mesh : passmesh)->xstart, passmesh), + ys(ymin), ye(ymax) { - location = BNDRY_XIN; - width = localmesh->xstart; x = width-1; // First point inside the boundary if(ye < ys) swap(ys, ye); @@ -58,10 +58,11 @@ bool BoundaryRegionXIn::isDone() BoundaryRegionXOut::BoundaryRegionXOut(std::string name, int ymin, int ymax, Mesh* passmesh) - : BoundaryRegion(name, 1, 0, passmesh), ys(ymin), ye(ymax) + : BoundaryRegion(name, 1, 0, BNDRY_XOUT, + (passmesh == nullptr ? mesh : passmesh)->LocalNx - (passmesh == nullptr ? mesh : passmesh)->xend - 1, + passmesh), + ys(ymin), ye(ymax) { - location = BNDRY_XOUT; - width = localmesh->LocalNx - localmesh->xend - 1; x = localmesh->LocalNx - width; // First point inside the boundary if(ye < ys) swap(ys, ye); @@ -112,10 +113,10 @@ bool BoundaryRegionXOut::isDone() BoundaryRegionYDown::BoundaryRegionYDown(std::string name, int xmin, int xmax, Mesh* passmesh) - : BoundaryRegion(name, 0, -1, passmesh), xs(xmin), xe(xmax) + : BoundaryRegion(name, 0, -1, BNDRY_YDOWN, + (passmesh == nullptr ? mesh : passmesh)->ystart, passmesh), + xs(xmin), xe(xmax) { - location = BNDRY_YDOWN; - width = localmesh->ystart; y = width-1; // First point inside the boundary if(xe < xs) swap(xs, xe); @@ -167,10 +168,11 @@ bool BoundaryRegionYDown::isDone() BoundaryRegionYUp::BoundaryRegionYUp(std::string name, int xmin, int xmax, Mesh* passmesh) - : BoundaryRegion(name, 0, 1, passmesh), xs(xmin), xe(xmax) + : BoundaryRegion(name, 0, 1, BNDRY_YUP, + (passmesh == nullptr ? mesh : passmesh)->LocalNy - (passmesh == nullptr ? mesh : passmesh)->yend - 1, + passmesh), + xs(xmin), xe(xmax) { - location = BNDRY_YUP; - width = localmesh->LocalNy - localmesh->yend - 1; y = localmesh->LocalNy - width; // First point inside the boundary if(xe < xs) swap(xs, xe); diff --git a/src/mesh/boundary_standard.cxx b/src/mesh/boundary_standard.cxx index 4cdd5361e0..0e536ac4b6 100644 --- a/src/mesh/boundary_standard.cxx +++ b/src/mesh/boundary_standard.cxx @@ -1432,50 +1432,6 @@ void BoundaryRelax::apply_ddt(Field3D &f) { /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryWidth::cloneMod(BoundaryOp *operation, const list &args) { - BoundaryWidth* result = new BoundaryWidth(operation, width); - - if (args.empty()) { - output << "WARNING: BoundaryWidth expected 1 argument\n"; - }else { - // First argument should be the rate - int val = stringToInt(args.front()); - result->width = val; - } - - return result; -} - -void BoundaryWidth::apply(Field2D &f, BoutReal t) { - // Pointer to boundary region shared between all BoundaryOp, BoundaryModifiers - int oldwid = bndry->width; - bndry->width = width; - op->apply(f, t); - bndry->width = oldwid; -} - -void BoundaryWidth::apply(Field3D &f, BoutReal t) { - int oldwid = bndry->width; - bndry->width = width; - op->apply(f, t); - bndry->width = oldwid; -} - -void BoundaryWidth::apply_ddt(Field2D &f) { - int oldwid = bndry->width; - bndry->width = width; - op->apply_ddt(f); - bndry->width = oldwid; -} - -void BoundaryWidth::apply_ddt(Field3D &f) { - int oldwid = bndry->width; - bndry->width = width; - op->apply_ddt(f); - bndry->width = oldwid; -} - -/////////////////////////////////////////////////////////////// BoundaryOp* BoundaryToFieldAligned::cloneMod(BoundaryOp *operation, const list &args) { BoundaryToFieldAligned* result = new BoundaryToFieldAligned(operation); From e38c010311c9d2e9d28922fc307bee8109431a81 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 31 Oct 2018 14:35:45 +0000 Subject: [PATCH 31/45] Implement width keyword for boundary conditions that don't take args except for a couple that implement their own special clone methods instead of calling boundaryCloneNoArguments. --- include/boundary_standard.hxx | 12 ++++-------- src/mesh/boundary_standard.cxx | 13 ++++++++----- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/include/boundary_standard.hxx b/include/boundary_standard.hxx index 004fbf1995..40943c8579 100644 --- a/include/boundary_standard.hxx +++ b/include/boundary_standard.hxx @@ -248,8 +248,7 @@ class BoundaryConstGradient : public BoundaryOp { /// Zero Laplacian, decaying solution class BoundaryZeroLaplace : public BoundaryOp { public: - BoundaryZeroLaplace() {} - BoundaryZeroLaplace(BoundaryRegion *region):BoundaryOp(region) { } + using BoundaryOp::BoundaryOp; BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; @@ -261,8 +260,7 @@ class BoundaryZeroLaplace : public BoundaryOp { /// Zero Laplacian class BoundaryZeroLaplace2 : public BoundaryOp { public: - BoundaryZeroLaplace2() {} - BoundaryZeroLaplace2(BoundaryRegion *region):BoundaryOp(region) { } + using BoundaryOp::BoundaryOp; BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; @@ -274,8 +272,7 @@ class BoundaryZeroLaplace2 : public BoundaryOp { /// Constant Laplacian, decaying solution class BoundaryConstLaplace : public BoundaryOp { public: - BoundaryConstLaplace() {} - BoundaryConstLaplace(BoundaryRegion *region):BoundaryOp(region) { } + using BoundaryOp::BoundaryOp; BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; @@ -287,8 +284,7 @@ class BoundaryConstLaplace : public BoundaryOp { /// Vector boundary condition Div(B) = 0, Curl(B) = 0 class BoundaryDivCurl : public BoundaryOp { public: - BoundaryDivCurl() {} - BoundaryDivCurl(BoundaryRegion *region):BoundaryOp(region) { } + using BoundaryOp::BoundaryOp; BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; diff --git a/src/mesh/boundary_standard.cxx b/src/mesh/boundary_standard.cxx index 0e536ac4b6..abbf967e19 100644 --- a/src/mesh/boundary_standard.cxx +++ b/src/mesh/boundary_standard.cxx @@ -156,12 +156,15 @@ namespace { if (!args.empty()) { output << "WARNING: Ignoring arguments to BoundaryOp for "<label<<" region\n"; } - if (!keywords.empty()) { - // Given keywords, but not using - throw BoutException("Keywords ignored in boundary : %s", keywords.begin()->first.c_str()); + int width = region->width; + for (const auto &it : keywords) { + if (it.first == "width") { + width = stringToInt(it.second); + } else { + throw BoutException("Unrecognized boundary condition keyword %s for %s boundary", it.first.c_str(), region->label.c_str()); + } } - - return new T(region); + return new T(region, width); } } From b62bc0f21048b637b91ef59bc133fc9166c89ccb Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 31 Oct 2018 16:47:10 +0000 Subject: [PATCH 32/45] Remove unused BoundaryOpRegion template Also change BoundaryRegionOp from using is_same to is_convertible, in case template needs to be used with subclasses of BoundaryRegion/BoundaryRegionPar. --- include/boundary_factory.hxx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/include/boundary_factory.hxx b/include/boundary_factory.hxx index ba1209367d..e6713f7c83 100644 --- a/include/boundary_factory.hxx +++ b/include/boundary_factory.hxx @@ -15,10 +15,7 @@ using std::string; using std::map; template -using BoundaryOpRegion = typename std::conditional::value, BoundaryRegionPar, BoundaryRegion>::type; - -template -using BoundaryRegionOp = typename std::conditional::value, BoundaryOpPar, BoundaryOp>::type; +using BoundaryRegionOp = typename std::conditional::value, BoundaryOpPar, BoundaryOp>::type; /// Create BoundaryOp objects on demand /*! From 773cf49b688d1f2ea5723e41b3af181b62de9777 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 31 Oct 2018 16:48:20 +0000 Subject: [PATCH 33/45] Update test_boundary_factory.cxx, compatible with refactored BoundaryOp --- tests/unit/mesh/test_boundary_factory.cxx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/unit/mesh/test_boundary_factory.cxx b/tests/unit/mesh/test_boundary_factory.cxx index 850eadd2f4..c6421f6ad1 100644 --- a/tests/unit/mesh/test_boundary_factory.cxx +++ b/tests/unit/mesh/test_boundary_factory.cxx @@ -20,8 +20,8 @@ class TestBoundary : public BoundaryOp { std::list args; std::map keywords; - void apply(Field2D &UNUSED(f)) override {} - void apply(Field3D &UNUSED(f)) override {} + void apply(Field2D &UNUSED(f), BoutReal UNUSED(t)) override {} + void apply(Field3D &UNUSED(f), BoutReal UNUSED(t)) override {} }; TEST(BoundaryFactoryTests, IsSingleton) { @@ -41,7 +41,7 @@ TEST(BoundaryFactoryTests, CreateTestBoundary) { // Check no brackets - auto *boundary = fac->create("testboundary", ®ion); + auto *boundary = fac->create("testboundary", ®ion); EXPECT_TRUE( boundary != nullptr ); @@ -51,7 +51,7 @@ TEST(BoundaryFactoryTests, CreateTestBoundary) { // Positional arguments - boundary = fac->create("testboundary(a, 1)", ®ion); + boundary = fac->create("testboundary(a, 1)", ®ion); EXPECT_TRUE( boundary != nullptr ); TestBoundary *tb = dynamic_cast(boundary); @@ -64,7 +64,7 @@ TEST(BoundaryFactoryTests, CreateTestBoundary) { delete boundary; // Test keywords - boundary = fac->create("testboundary(key=1, b=value)", ®ion); + boundary = fac->create("testboundary(key=1, b=value)", ®ion); EXPECT_TRUE( boundary != nullptr ); tb = dynamic_cast(boundary); @@ -77,7 +77,7 @@ TEST(BoundaryFactoryTests, CreateTestBoundary) { delete boundary; // Mix of positional args and keywords - boundary = fac->create("testboundary(0.23, key =1+2 , something(),b=value ,a + sin(1.2))", ®ion); + boundary = fac->create("testboundary(0.23, key =1+2 , something(),b=value ,a + sin(1.2))", ®ion); EXPECT_TRUE( boundary != nullptr ); tb = dynamic_cast(boundary); From b24822581961602b017b1d5a5343b56a03dc1af5 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 30 Oct 2018 09:47:02 +0000 Subject: [PATCH 34/45] Example to time application of boundary conditions --- .../apply-boundary/apply-boundary.cxx | 132 ++++++++++++++++++ .../performance/apply-boundary/data/BOUT.inp | 33 +++++ examples/performance/apply-boundary/makefile | 5 + 3 files changed, 170 insertions(+) create mode 100644 examples/performance/apply-boundary/apply-boundary.cxx create mode 100644 examples/performance/apply-boundary/data/BOUT.inp create mode 100644 examples/performance/apply-boundary/makefile diff --git a/examples/performance/apply-boundary/apply-boundary.cxx b/examples/performance/apply-boundary/apply-boundary.cxx new file mode 100644 index 0000000000..cd5431bed6 --- /dev/null +++ b/examples/performance/apply-boundary/apply-boundary.cxx @@ -0,0 +1,132 @@ +#include +#include + +class BoundaryOp_timing : public PhysicsModel { + int init(bool restarting); + int rhs(BoutReal UNUSED(t)) { return 1; } + Field3D f_dirichlet, f_neumann, f_dirichlet_o3; + Field3D f_dirichlet_val, f_neumann_val, f_dirichlet_o3_val; + Field3D f_dirichlet_expr, f_neumann_expr, f_dirichlet_o3_expr; +}; + +int BoundaryOp_timing::init(bool UNUSED(restarting)) { + SOLVE_FOR3(f_dirichlet, f_neumann, f_dirichlet_o3); + SOLVE_FOR3(f_dirichlet_val, f_neumann_val, f_dirichlet_o3_val); + SOLVE_FOR3(f_dirichlet_expr, f_neumann_expr, f_dirichlet_o3_expr); + + Options* opt = Options::getRoot(); + int ntests; + OPTION(opt, ntests, 10000); + + + // test Dirichlet_O3 + + { + Timer timer("dirichlet_o3"); + for (int i=0; i Date: Tue, 30 Oct 2018 10:52:03 +0000 Subject: [PATCH 35/45] Implement CRTP pattern for BoundaryOpWithApply BoundaryOp implementations (e.g. BoundaryNeumann, etc.) that use a default 'apply()' method provided by a base class now inherit from BoundaryOpWithApply, which is templated on the derived class type. This means that its 'apply()' method can use static methods of the derived class directly, so that they can be inlined. This should improve performance when optimization is turned on. CRTP pattern: https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern --- include/boundary_op.hxx | 75 ++++---- include/boundary_standard.hxx | 327 +++++++++++++++++---------------- src/mesh/boundary_op.cxx | 224 ---------------------- src/mesh/boundary_standard.cxx | 304 ++++++++++++++++++++++++++++-- 4 files changed, 494 insertions(+), 436 deletions(-) diff --git a/include/boundary_op.hxx b/include/boundary_op.hxx index bf61c453ae..d4f8b690fa 100644 --- a/include/boundary_op.hxx +++ b/include/boundary_op.hxx @@ -41,12 +41,8 @@ public: /// Apply a boundary condition on field f - virtual void apply(Field2D &f,BoutReal t = 0.) { - applyTemplate(f, t); - } - virtual void apply(Field3D &f,BoutReal t = 0.) { - applyTemplate(f, t); - } + virtual void apply(Field2D &f, BoutReal t = 0.) = 0; + virtual void apply(Field3D &f, BoutReal t = 0.) = 0; virtual void apply(Vector2D &f) { apply(f.x); @@ -72,46 +68,51 @@ public: BoundaryRegion *bndry; const bool apply_to_ddt; // True if this boundary condition should be applied on the time derivatives, false if it should be applied to the field values - protected: std::shared_ptr gen; // Generator const int width; // boundary width, stored in case we change it from the default +}; - // Apply boundary condition at a point - virtual void applyAtPoint(Field2D &UNUSED(f), BoutReal UNUSED(val), int - UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), - Coordinates* UNUSED(metric)) { - throw BoutException("BoundaryOp::applyAtPoint() should never be called. A " - "subclass should either override BoundaryOp::apply() or override " - "applyAtPoint() and applyAtPointStaggered()."); - } - virtual void applyAtPoint(Field3D &UNUSED(f), BoutReal UNUSED(val), int - UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), - Coordinates* UNUSED(metric)) { - throw BoutException("BoundaryOp::applyAtPoint() should never be called. A " - "subclass should either override BoundaryOp::apply() or override " - "applyAtPoint() and applyAtPointStaggered()."); +/// An operation on a boundary +template +class BoundaryOpWithApply : public BoundaryOp { +public: + using BoundaryOp::BoundaryOp; + + // Note: All methods must implement clone, except for modifiers (see below) + virtual BoundaryOp* clone(BoundaryRegion *UNUSED(region), const list &UNUSED(args)) { + ASSERT1(false); // this implementation should never get called + return nullptr; } - // Apply to staggered grid - virtual void applyAtPointStaggered(Field2D &UNUSED(f), BoutReal UNUSED(val), - int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int - UNUSED(z), Coordinates* UNUSED(metric)) { - throw BoutException("BoundaryOp::applyAtPointStaggered() should never be " - "called. A subclass should either override BoundaryOp::apply() or " - "override applyAtPoint() and applyAtPointStaggered()."); + /// Apply a boundary condition on field f + void apply(Field2D &f, BoutReal t = 0.) override { + applyTemplate(f, t); } - virtual void applyAtPointStaggered(Field3D &UNUSED(f), BoutReal UNUSED(val), - int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int - UNUSED(z), Coordinates* UNUSED(metric)) { - throw BoutException("BoundaryOp::applyAtPointStaggered() should never be " - "called. A subclass should either override BoundaryOp::apply() or " - "override applyAtPoint() and applyAtPointStaggered()."); + void apply(Field3D &f, BoutReal t = 0.) override { + applyTemplate(f, t); } - // extrapolate to further guard cells - virtual void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); - virtual void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); +protected: + //// Apply boundary condition at a point + //virtual void applyAtPoint(Field2D &UNUSED(f), BoutReal UNUSED(val), int + // UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), + // Coordinates* UNUSED(metric)) = 0; + //virtual void applyAtPoint(Field3D &UNUSED(f), BoutReal UNUSED(val), int + // UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), + // Coordinates* UNUSED(metric)) = 0; + + //// Apply to staggered grid + //virtual void applyAtPointStaggered(Field2D &UNUSED(f), BoutReal UNUSED(val), + // int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int + // UNUSED(z), Coordinates* UNUSED(metric)) = 0; + //virtual void applyAtPointStaggered(Field3D &UNUSED(f), BoutReal UNUSED(val), + // int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int + // UNUSED(z), Coordinates* UNUSED(metric)) = 0; + + //// extrapolate to further guard cells + //virtual void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) = 0; + //virtual void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) = 0; private: template diff --git a/include/boundary_standard.hxx b/include/boundary_standard.hxx index 40943c8579..148b11b438 100644 --- a/include/boundary_standard.hxx +++ b/include/boundary_standard.hxx @@ -17,11 +17,10 @@ class BoundaryDirichlet : public BoundaryOp { BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - using BoundaryOp::apply; - void apply(Field2D &f,BoutReal t = 0.) override { + void apply(Field2D &f,BoutReal t = 0.) final { applyTemplate(f, t); } - void apply(Field3D &f,BoutReal t = 0.) override { + void apply(Field3D &f,BoutReal t = 0.) final { applyTemplate(f, t); } @@ -33,74 +32,78 @@ class BoundaryDirichlet : public BoundaryOp { BoutReal default_func(BoutReal t, int x, int y, int z); /// 3nd-order boundary condition -class BoundaryDirichlet_O3 : public BoundaryOp { +class BoundaryDirichlet_O3 : public BoundaryOpWithApply { public: - using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors + using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOp constructors BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) override; - void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) override; - void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) override; - void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) override; + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)); + static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); + static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; /// 4th-order boundary condition -class BoundaryDirichlet_O4 : public BoundaryOp { +class BoundaryDirichlet_O4 : public BoundaryOpWithApply { public: - using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors + using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) override; - void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) override; - void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) override; - void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) override; + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)); + static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); + static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; /// Dirichlet boundary condition, tries to smooth out grid-scale oscillations at the boundary -class BoundaryDirichlet_smooth : public BoundaryOp { +class BoundaryDirichlet_smooth : public BoundaryOpWithApply { public: - using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors + using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) override; - void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) override; + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)); + static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); + static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; /// Dirichlet boundary condition set half way between guard cell and grid cell at 2nd order accuracy -class BoundaryDirichlet_2ndOrder : public BoundaryOp { +class BoundaryDirichlet_2ndOrder : public BoundaryOpWithApply { public: - using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors + using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) override; - void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) override; + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)); + static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); + static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; /// Dirichlet boundary condition set half way between guard cell and grid cell at 4th order accuracy -class BoundaryDirichlet_O5 : public BoundaryOp { +class BoundaryDirichlet_O5 : public BoundaryOpWithApply { public: - using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors + using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) override; - void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) override; - void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) override; - void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) override; + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)); + static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); + static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; /// Neumann (zero-gradient) boundary condition for non-orthogonal meshes @@ -112,11 +115,10 @@ class BoundaryNeumann_NonOrthogonal : public BoundaryOp { BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - using BoundaryOp::apply; - void apply(Field2D &f, BoutReal t = 0.) override { + void apply(Field2D &f, BoutReal t = 0.) final { applyTemplate(f, t); } - void apply(Field3D &f, BoutReal t = 0.) override { + void apply(Field3D &f, BoutReal t = 0.) final { applyTemplate(f, t); } private: @@ -127,86 +129,94 @@ class BoundaryNeumann_NonOrthogonal : public BoundaryOp { }; /// Neumann (zero-gradient) boundary condition, using 2nd order on boundary -class BoundaryNeumann2 : public BoundaryOp { +class BoundaryNeumann2 : public BoundaryOpWithApply { public: - using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors + using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); + static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; /// Neumann boundary condition set half way between guard cell and grid cell at 2nd order accuracy -class BoundaryNeumann_2ndOrder : public BoundaryOp { +class BoundaryNeumann_2ndOrder : public BoundaryOpWithApply { public: - using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors + using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); + static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; // Neumann boundary condition set half way between guard cell and grid cell at 2nd order accuracy -class BoundaryNeumann : public BoundaryOp { +class BoundaryNeumann : public BoundaryOpWithApply { public: - using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors + using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; - void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; - void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); + static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; /// Neumann boundary condition set half way between guard cell and grid cell at 4th order accuracy -class BoundaryNeumann_O4 : public BoundaryOp { +class BoundaryNeumann_O4 : public BoundaryOpWithApply { public: - using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors + using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; - void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; - void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) override; - void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) override; + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); + static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; /// Neumann boundary condition set half way between guard cell and grid cell at 4th order accuracy -class BoundaryNeumann_4thOrder : public BoundaryOp { +class BoundaryNeumann_4thOrder : public BoundaryOpWithApply { public: - using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors + using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; - void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; - void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) override; - void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) override; + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); + static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; /// NeumannPar (zero-gradient) boundary condition on /// the variable / sqrt(g_22) -class BoundaryNeumannPar : public BoundaryOp { +class BoundaryNeumannPar : public BoundaryOpWithApply { public: - using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors + using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; - void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; - void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); + static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; /// Robin (mix of Dirichlet and Neumann) @@ -218,11 +228,10 @@ class BoundaryRobin : public BoundaryOp { BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - using BoundaryOp::apply; - void apply(Field2D &f, BoutReal t = 0.) override { + void apply(Field2D &f, BoutReal t = 0.) final { applyTemplate(f, t); } - void apply(Field3D &f, BoutReal t = 0.) override { + void apply(Field3D &f, BoutReal t = 0.) final { applyTemplate(f, t); } private: @@ -233,16 +242,18 @@ private: }; /// Constant gradient (zero second derivative) -class BoundaryConstGradient : public BoundaryOp { +class BoundaryConstGradient : public BoundaryOpWithApply { public: - using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors + using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); + static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; /// Zero Laplacian, decaying solution @@ -252,9 +263,8 @@ class BoundaryZeroLaplace : public BoundaryOp { BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - using BoundaryOp::apply; - void apply(Field2D &f, BoutReal UNUSED(t)) override; - void apply(Field3D &f, BoutReal UNUSED(t)) override; + void apply(Field2D &f, BoutReal UNUSED(t)) final; + void apply(Field3D &f, BoutReal UNUSED(t)) final; }; /// Zero Laplacian @@ -264,9 +274,8 @@ class BoundaryZeroLaplace2 : public BoundaryOp { BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - using BoundaryOp::apply; - void apply(Field2D &f, BoutReal t) override; - void apply(Field3D &f, BoutReal t) override; + void apply(Field2D &f, BoutReal t) final; + void apply(Field3D &f, BoutReal t) final; }; /// Constant Laplacian, decaying solution @@ -276,9 +285,8 @@ class BoundaryConstLaplace : public BoundaryOp { BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - using BoundaryOp::apply; - void apply(Field2D &f, BoutReal t) override; - void apply(Field3D &f, BoutReal t) override; + void apply(Field2D &f, BoutReal t) final; + void apply(Field3D &f, BoutReal t) final; }; /// Vector boundary condition Div(B) = 0, Curl(B) = 0 @@ -288,86 +296,85 @@ class BoundaryDivCurl : public BoundaryOp { BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - using BoundaryOp::apply; - void apply(Field2D &UNUSED(f), BoutReal UNUSED(t)) override { throw BoutException("ERROR: DivCurl boundary only for vectors"); } - void apply(Field3D &UNUSED(f), BoutReal UNUSED(t)) override { throw BoutException("ERROR: DivCurl boundary only for vectors"); } - void apply(Vector2D &f) override; - void apply(Vector3D &f) override; + void apply(Field2D &UNUSED(f), BoutReal UNUSED(t)) final { throw BoutException("ERROR: DivCurl boundary only for vectors"); } + void apply(Field3D &UNUSED(f), BoutReal UNUSED(t)) final { throw BoutException("ERROR: DivCurl boundary only for vectors"); } + void apply(Vector2D &f) final; + void apply(Vector3D &f) final; }; /// Free boundary condition (evolve the field in the guard cells, using non-centred derivatives to calculate the ddt) class BoundaryFree : public BoundaryOp { public: - using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors + using BoundaryOp::BoundaryOp; // inherit BoundaryOpWithApply constructors BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - using BoundaryOp::apply; - void apply(Field2D &f, BoutReal UNUSED(t)) override; - void apply(Field3D &f, BoutReal UNUSED(t)) override; + void apply(Field2D &f, BoutReal UNUSED(t)) final; + void apply(Field3D &f, BoutReal UNUSED(t)) final; - using BoundaryOp::apply_ddt; - void apply_ddt(Field2D &f) override; - void apply_ddt(Field3D &f) override; + void apply_ddt(Field2D &f) final; + void apply_ddt(Field3D &f) final; private: BoutReal val; }; // L. Easy /// Alternative free boundary condition (evolve the field in the guard cells, using non-centred derivatives to calculate the ddt) -class BoundaryFree_O2 : public BoundaryOp { +class BoundaryFree_O2 : public BoundaryOpWithApply { public: - using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors + using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); + static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; -class BoundaryFree_O3 : public BoundaryOp { +class BoundaryFree_O3 : public BoundaryOpWithApply { public: - using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors + using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; - void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; - void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) override; - void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) override; + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); + static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; // End L.Easy -class BoundaryFree_O4 : public BoundaryOp { +class BoundaryFree_O4 : public BoundaryOpWithApply { public: - using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors + using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; - void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; - void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) override; - void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) override; + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); + static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; -class BoundaryFree_O5 : public BoundaryOp { +class BoundaryFree_O5 : public BoundaryOpWithApply { public: - using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors + using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; - void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) override; - void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) override; - void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) override; - void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) override; + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); + static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; ///////////////////////////////////////////////////////// @@ -377,15 +384,13 @@ class BoundaryRelax : public BoundaryModifier { public: BoundaryRelax() : BoundaryModifier(true), r(10.) {} // Set default rate BoundaryRelax(BoundaryOp *operation, BoutReal rate) : BoundaryModifier(operation, true) { r = fabs(rate); } - BoundaryOp* cloneMod(BoundaryOp *op, const list &args) override; + BoundaryOp* cloneMod(BoundaryOp *op, const list &args) final; - using BoundaryModifier::apply; - void apply(Field2D &f, BoutReal t) override; - void apply(Field3D &f, BoutReal t) override; + void apply(Field2D &f, BoutReal t) final; + void apply(Field3D &f, BoutReal t) final; - using BoundaryModifier::apply_ddt; - void apply_ddt(Field2D &f) override; - void apply_ddt(Field3D &f) override; + void apply_ddt(Field2D &f) final; + void apply_ddt(Field3D &f) final; private: BoutReal r; }; @@ -415,15 +420,13 @@ class BoundaryToFieldAligned : public BoundaryModifier { public: BoundaryToFieldAligned(){} BoundaryToFieldAligned(BoundaryOp *operation) : BoundaryModifier(operation){} - BoundaryOp* cloneMod(BoundaryOp *op, const list &args) override; + BoundaryOp* cloneMod(BoundaryOp *op, const list &args) final; - using BoundaryModifier::apply; - void apply(Field2D &f, BoutReal t) override; - void apply(Field3D &f, BoutReal t) override; + void apply(Field2D &f, BoutReal t) final; + void apply(Field3D &f, BoutReal t) final; - using BoundaryModifier::apply_ddt; - void apply_ddt(Field2D &f) override; - void apply_ddt(Field3D &f) override; + void apply_ddt(Field2D &f) final; + void apply_ddt(Field3D &f) final; private: }; @@ -433,15 +436,13 @@ class BoundaryFromFieldAligned : public BoundaryModifier { public: BoundaryFromFieldAligned(){} BoundaryFromFieldAligned(BoundaryOp *operation) : BoundaryModifier(operation){} - BoundaryOp* cloneMod(BoundaryOp *op, const list &args) override; + BoundaryOp* cloneMod(BoundaryOp *op, const list &args) final; - using BoundaryModifier::apply; - void apply(Field2D &f, BoutReal t) override; - void apply(Field3D &f, BoutReal t) override; + void apply(Field2D &f, BoutReal t) final; + void apply(Field3D &f, BoutReal t) final; - using BoundaryModifier::apply_ddt; - void apply_ddt(Field2D &f) override; - void apply_ddt(Field3D &f) override; + void apply_ddt(Field2D &f) final; + void apply_ddt(Field3D &f) final; private: }; diff --git a/src/mesh/boundary_op.cxx b/src/mesh/boundary_op.cxx index 44ecc4efd0..d3cc7278a3 100644 --- a/src/mesh/boundary_op.cxx +++ b/src/mesh/boundary_op.cxx @@ -24,230 +24,6 @@ #include #include -void BoundaryOp::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { - f(x, y, z) = 2.0*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z); -} -void BoundaryOp::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { - f(x, y, z) = 2.0*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z); -} - -template -void BoundaryOp::applyTemplate(T &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(); - Coordinates* metric = f.getCoordinates(); - - // Check for staggered grids - CELL_LOC loc = f.getLocation(); - - bndry->first(); - - // Decide which generator to use - std::shared_ptr fg = gen; - if (!fg) { - fg = f.getBndryGenerator(bndry->location); - } - - BoutReal val = 0.0; - - if (loc == CELL_CENTRE) { - // no staggering - 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 - - BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) // In the guard cell - + localmesh->GlobalY(bndry->y - bndry->by) ); // the grid cell - - for(int z=0; zGlobalZ(z); - if (fg) { - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); - } - applyAtPoint(f, val, bndry->x, bndry->bx, bndry->y, bndry->by, z, metric); - - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for (int i = 1; i < bndry->width; i++) { - int x = bndry->x + i*bndry->bx; - int y = bndry->y + i*bndry->by; - extrapolateFurther(f, x, bndry->bx, y, bndry->by, z); - } - } - } - } - else 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 z=0; zGlobalZ(z); - if (fg) { - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); - } - applyAtPointStaggered(f, val, bndry->x, bndry->bx, bndry->y, 0, z, metric); - - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for (int i = 1; i < bndry->width; i++) { - int x = bndry->x + i*bndry->bx; - extrapolateFurther(f, x, bndry->bx, bndry->y, 0, z); - } - } - } - } else 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 z=0; zGlobalZ(z); - if (fg) { - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); - } - // Set one point inwards - applyAtPointStaggered(f, val, bndry->x + 1, bndry->bx, bndry->y, 0, z, metric); - - // Need to set second and third guard cells, as may be used for interpolation or upwinding derivatives - for (int i = 0; i < bndry->width; i++) { - int x = bndry->x + i*bndry->bx; - extrapolateFurther(f, x, bndry->bx, bndry->y, 0, z); - } - } - } - } else 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 z=0; zGlobalZ(z); - if (fg) { - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); - } - applyAtPoint(f, val, bndry->x, 0, bndry->y, bndry->by, z, metric); - - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=1;iwidth;i++) { - int y = bndry->y + i*bndry->by; - extrapolateFurther(f, bndry->x, 0, y, bndry->by, z); - } - } - } - } - } 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 z=0; zGlobalZ(z); - if (fg) { - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); - } - applyAtPointStaggered(f, val, bndry->x, 0, bndry->y, bndry->by, z, metric); - - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=1;iwidth;i++) { - int y = bndry->y + i*bndry->by; - extrapolateFurther(f, bndry->x, 0, y, bndry->by, z); - } - } - } - } else 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 z=0; zGlobalZ(z); - if (fg) { - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); - } - applyAtPointStaggered(f, val, bndry->x, 0, bndry->y+1, bndry->by, z, metric); - - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=0;iwidth;i++) { - int y = bndry->y + i*bndry->by; - extrapolateFurther(f, bndry->x, 0, y, bndry->by, z); - } - } - } - } else 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 z=0; zGlobalZ(z); - if (fg) { - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); - } - - applyAtPoint(f, val, bndry->x, bndry->bx, bndry->y, 0, z, metric); - - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=1;iwidth;i++) { - int x = bndry->x + i*bndry->bx; - extrapolateFurther(f, x, bndry->bx, bndry->y, 0, z); - } - } - } - } - } else if (loc == CELL_ZLOW) { - // Staggered in Z. Note there are no z-boundaries. - 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 - - BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) // In the guard cell - + localmesh->GlobalY(bndry->y - bndry->by) ); // the grid cell - - for(int z=0; zgenerate should be periodic in z - BoutReal znorm = 0.5*( localmesh->GlobalZ(z) + localmesh->GlobalZ(z - 1) ); // znorm is shifted by half a grid point because it is staggered - if (fg) { - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); - } - applyAtPoint(f, val, bndry->x, bndry->bx, bndry->y, bndry->by, z, metric); - - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for (int i = 1; i < bndry->width; i++) { - int x = bndry->x + i*bndry->bx; - int y = bndry->y + i*bndry->by; - extrapolateFurther(f, x, bndry->bx, y, bndry->by, z); - } - } - } - } -} -//// instantiate template for Field2D and Field3D -//template -//void BoundaryOp::applyTemplate(Field2D &f,BoutReal t); -//template -//void BoundaryOp::applyTemplate(Field3D &f,BoutReal t); - void BoundaryOp::apply_ddt(Field2D &f) { Field2D *dt = f.timeDeriv(); for(bndry->first(); !bndry->isDone(); bndry->next()) diff --git a/src/mesh/boundary_standard.cxx b/src/mesh/boundary_standard.cxx index abbf967e19..9dbc299e06 100644 --- a/src/mesh/boundary_standard.cxx +++ b/src/mesh/boundary_standard.cxx @@ -170,6 +170,227 @@ namespace { /////////////////////////////////////////////////////////////// +// Apply method for templated (CRTP pattern) BoundaryOpWithApply base class. +// Included here so it's in the same 'translation unit' as the implementations, +// so will be instantiated for each 'Derived'. + +template +template +void BoundaryOpWithApply::applyTemplate(T &f,BoutReal t) { + + // Convert the pointer to have the type of the final implementation class, so + // we can use the single-point methods directly + //Derived* this_derived = (Derived*) this; + + Mesh* localmesh = f.getMesh(); + Coordinates* metric = f.getCoordinates(); + + // Check for staggered grids + CELL_LOC loc = f.getLocation(); + + bndry->first(); + + // Decide which generator to use + std::shared_ptr fg = gen; + if (!fg) { + fg = f.getBndryGenerator(bndry->location); + } + + BoutReal val = 0.0; + + if (loc == CELL_CENTRE) { + // no staggering + 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 + + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) // In the guard cell + + localmesh->GlobalY(bndry->y - bndry->by) ); // the grid cell + + for(int z=0; zGlobalZ(z); + if (fg) { + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + } + Derived::applyAtPoint(f, val, bndry->x, bndry->bx, bndry->y, bndry->by, z, metric); + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for (int i = 1; i < width; i++) { + int x = bndry->x + i*bndry->bx; + int y = bndry->y + i*bndry->by; + Derived::extrapolateFurther(f, x, bndry->bx, y, bndry->by, z); + } + } + } + } + else 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 z=0; zGlobalZ(z); + if (fg) { + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + } + Derived::applyAtPointStaggered(f, val, bndry->x, bndry->bx, bndry->y, 0, z, metric); + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for (int i = 1; i < width; i++) { + int x = bndry->x + i*bndry->bx; + Derived::extrapolateFurther(f, x, bndry->bx, bndry->y, 0, z); + } + } + } + } else 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 z=0; zGlobalZ(z); + if (fg) { + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + } + // Set one point inwards + Derived::applyAtPointStaggered(f, val, bndry->x + 1, bndry->bx, bndry->y, 0, z, metric); + + // Need to set second and third guard cells, as may be used for interpolation or upwinding derivatives + for (int i = 0; i < width; i++) { + int x = bndry->x + i*bndry->bx; + Derived::extrapolateFurther(f, x, bndry->bx, bndry->y, 0, z); + } + } + } + } else 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 z=0; zGlobalZ(z); + if (fg) { + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + } + Derived::applyAtPoint(f, val, bndry->x, 0, bndry->y, bndry->by, z, metric); + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=1;iy + i*bndry->by; + Derived::extrapolateFurther(f, bndry->x, 0, y, bndry->by, z); + } + } + } + } + } 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 z=0; zGlobalZ(z); + if (fg) { + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + } + Derived::applyAtPointStaggered(f, val, bndry->x, 0, bndry->y, bndry->by, z, metric); + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=1;iy + i*bndry->by; + Derived::extrapolateFurther(f, bndry->x, 0, y, bndry->by, z); + } + } + } + } else 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 z=0; zGlobalZ(z); + if (fg) { + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + } + Derived::applyAtPointStaggered(f, val, bndry->x, 0, bndry->y+1, bndry->by, z, metric); + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=0;iy + i*bndry->by; + Derived::extrapolateFurther(f, bndry->x, 0, y, bndry->by, z); + } + } + } + } else 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 z=0; zGlobalZ(z); + if (fg) { + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + } + + Derived::applyAtPoint(f, val, bndry->x, bndry->bx, bndry->y, 0, z, metric); + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=1;ix + i*bndry->bx; + Derived::extrapolateFurther(f, x, bndry->bx, bndry->y, 0, z); + } + } + } + } + } else if (loc == CELL_ZLOW) { + // Staggered in Z. Note there are no z-boundaries. + 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 + + BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) // In the guard cell + + localmesh->GlobalY(bndry->y - bndry->by) ); // the grid cell + + for(int z=0; zgenerate should be periodic in z + BoutReal znorm = 0.5*( localmesh->GlobalZ(z) + localmesh->GlobalZ(z - 1) ); // znorm is shifted by half a grid point because it is staggered + if (fg) { + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + } + Derived::applyAtPoint(f, val, bndry->x, bndry->bx, bndry->y, bndry->by, z, metric); + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for (int i = 1; i < width; i++) { + int x = bndry->x + i*bndry->bx; + int y = bndry->y + i*bndry->by; + Derived::extrapolateFurther(f, x, bndry->bx, y, bndry->by, z); + } + } + } + } +} + +/////////////////////////////////////////////////////////////// + BoundaryOp* BoundaryDirichlet::clone(BoundaryRegion *region, const list &args, const std::map &keywords) { return boundaryClone(region, args, keywords); @@ -233,7 +454,7 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal t) { // i.e. elsewhere we tend to extrapolate. // // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - // for(int i=1;iwidth;i++) { + // for(int i=1;ix + i*bndry->bx; // int yi = bndry->y + i*bndry->by; @@ -246,7 +467,7 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal t) { // This loop is our alternative approach to setting the rest of the boundary // points. Instead of extrapolating we just use the generated values. This // can help with the stability of higher order methods. - for (int i = 1; i < bndry->width; i++) { + for (int i = 1; i < width; i++) { // 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; @@ -278,7 +499,7 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal 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++) { + for(int i=1;ix + i*bndry->bx; int yi = bndry->y ; @@ -302,7 +523,7 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal t) { f(bndry->x - bndry->bx,bndry->y, zk) = val; // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=0;iwidth;i++) { + for(int i=0;ix + i*bndry->bx; int yi = bndry->y ; @@ -326,7 +547,7 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal 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++) { + for(int i=1;ix ; int yi = bndry->y + i*bndry->by; @@ -350,7 +571,7 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal 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++) { + for(int i=1;ix ; int yi = bndry->y + i*bndry->by; @@ -373,7 +594,7 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal 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++) { + for(int i=0;ix ; int yi = bndry->y + i*bndry->by; @@ -398,7 +619,7 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal 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++) { + for(int i=1;ix + i*bndry->bx; int yi = bndry->y ; @@ -426,7 +647,7 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal 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++) { + for(int i=1;ix + i*bndry->bx; int yi = bndry->y ; @@ -521,6 +742,14 @@ void BoundaryDirichlet_smooth::applyAtPointStaggered(Field2D &f, BoutReal val, i void BoundaryDirichlet_smooth::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) { f(x, y, z) = val; } + +void BoundaryDirichlet_smooth::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { + extrapolate2nd(f, x, bx, y, by, z); +} +void BoundaryDirichlet_smooth::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { + extrapolate2nd(f, x, bx, y, by, z); +} + /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryDirichlet_2ndOrder::clone(BoundaryRegion *region, const list &args, @@ -546,6 +775,13 @@ void BoundaryDirichlet_2ndOrder::applyAtPointStaggered(Field3D &f, BoutReal val, f(x, y, z) = val; } +void BoundaryDirichlet_2ndOrder::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { + extrapolate2nd(f, x, bx, y, by, z); +} +void BoundaryDirichlet_2ndOrder::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { + extrapolate2nd(f, x, bx, y, by, z); +} + /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryDirichlet_O5::clone(BoundaryRegion *region, const list &args, @@ -621,7 +857,7 @@ void BoundaryNeumann_NonOrthogonal::applyTemplate(T &f, BoutReal UNUSED(t)) { // x boundaries only BoutReal delta = bndry->bx*metric->dx(bndry->x, bndry->y); f(bndry->x, bndry->y, z) = f(bndry->x - bndry->bx, bndry->y, z) + delta/g11shift*(val - xshift); - if (bndry->width == 2) { + if (width == 2) { f(bndry->x + bndry->bx, bndry->y, z) = f(bndry->x - 2*bndry->bx, bndry->y, z) + 3.0*delta/g11shift*(val - xshift); } } else if (bndry->by != 0 && bndry->bx == 0) { @@ -629,13 +865,13 @@ void BoundaryNeumann_NonOrthogonal::applyTemplate(T &f, BoutReal UNUSED(t)) { // no need to shift this b/c we want parallel nuemann not theta BoutReal delta = bndry->by*metric->dy(bndry->x, bndry->y); f(bndry->x, bndry->y, z) = f(bndry->x, bndry->y - bndry->by, z) + delta*val; - if (bndry->width == 2) { + if (width == 2) { f(bndry->x, bndry->y + bndry->by, z) = f(bndry->x, bndry->y - 2*bndry->by, z) + 3.0*delta*val; } } else { // set corners to zero f(bndry->x, bndry->y, z) = 0.0; - if (bndry->width == 2) { + if (width == 2) { f(bndry->x + bndry->bx, bndry->y + bndry->by, z) = 0.0; } } @@ -666,6 +902,13 @@ void BoundaryNeumann2::applyAtPointStaggered(Field3D &UNUSED(f), BoutReal UNUSED throw BoutException("BoundaryNeumann2 not implemented for staggered grids"); } +void BoundaryNeumann2::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { + extrapolate2nd(f, x, bx, y, by, z); +} +void BoundaryNeumann2::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { + extrapolate2nd(f, x, bx, y, by, z); +} + /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryNeumann_2ndOrder::clone(BoundaryRegion *region, const list &args, @@ -693,6 +936,14 @@ void BoundaryNeumann_2ndOrder::applyAtPointStaggered(Field3D &f, BoutReal val, i f(x, y, z) = (4.*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z) + 2.*delta*val)/3.; } +void BoundaryNeumann_2ndOrder::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { + extrapolate2nd(f, x, bx, y, by, z); +} +void BoundaryNeumann_2ndOrder::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { + extrapolate2nd(f, x, bx, y, by, z); +} + + /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryNeumann::clone(BoundaryRegion *region, const list &args, @@ -720,6 +971,14 @@ void BoundaryNeumann::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int f(x, y, z) = (4.*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z) + 2.*delta*val)/3.; } +void BoundaryNeumann::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { + extrapolate2nd(f, x, bx, y, by, z); +} +void BoundaryNeumann::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { + extrapolate2nd(f, x, bx, y, by, z); +} + + /////////////////////////////////////////////////////////////// @@ -822,6 +1081,13 @@ void BoundaryNeumannPar::applyAtPointStaggered(Field3D &UNUSED(f), BoutReal UNUS throw BoutException("BoundaryNeumannPar is not implemented for staggered grids."); } +void BoundaryNeumannPar::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { + extrapolate2nd(f, x, bx, y, by, z); +} +void BoundaryNeumannPar::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { + extrapolate2nd(f, x, bx, y, by, z); +} + /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryRobin::clone(BoundaryRegion *region, const list &args, @@ -898,6 +1164,13 @@ void BoundaryConstGradient::applyAtPointStaggered(Field3D &UNUSED(f), BoutReal U throw BoutException("BoundaryConstGradient is not implemented for staggered grids."); } +void BoundaryConstGradient::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { + extrapolate2nd(f, x, bx, y, by, z); +} +void BoundaryConstGradient::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { + extrapolate2nd(f, x, bx, y, by, z); +} + /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryZeroLaplace::clone(BoundaryRegion *region, const list &args, @@ -1293,6 +1566,13 @@ void BoundaryFree_O2::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), in extrapolate2nd(f, x, bx, y, by, z); } +void BoundaryFree_O2::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { + extrapolate2nd(f, x, bx, y, by, z); +} +void BoundaryFree_O2::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { + extrapolate2nd(f, x, bx, y, by, z); +} + ////////////////////////////////// // Third order extrapolation: ////////////////////////////////// From 3c0c6a391ce5212f65a504b543682d73f81520c6 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 30 Oct 2018 18:06:43 +0000 Subject: [PATCH 36/45] Pass (BoutReal) grid spacing instead of Coordinates* --- include/boundary_op.hxx | 2 +- include/boundary_standard.hxx | 165 ++++++++++++----------- src/mesh/boundary_standard.cxx | 240 ++++++++++++++++++--------------- 3 files changed, 220 insertions(+), 187 deletions(-) diff --git a/include/boundary_op.hxx b/include/boundary_op.hxx index d4f8b690fa..4f38510773 100644 --- a/include/boundary_op.hxx +++ b/include/boundary_op.hxx @@ -74,7 +74,7 @@ protected: }; /// An operation on a boundary -template +template class BoundaryOpWithApply : public BoundaryOp { public: using BoundaryOp::BoundaryOp; diff --git a/include/boundary_standard.hxx b/include/boundary_standard.hxx index 148b11b438..f4900f012f 100644 --- a/include/boundary_standard.hxx +++ b/include/boundary_standard.hxx @@ -38,10 +38,10 @@ class BoundaryDirichlet_O3 : public BoundaryOpWithApply { BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); - static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); - static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)); - static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)); + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; @@ -53,10 +53,10 @@ class BoundaryDirichlet_O4 : public BoundaryOpWithApply { BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); - static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); - static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)); - static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)); + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; @@ -68,10 +68,10 @@ class BoundaryDirichlet_smooth : public BoundaryOpWithApply &args, const std::map &keywords) override; - static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); - static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); - static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)); - static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)); + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; @@ -83,10 +83,10 @@ class BoundaryDirichlet_2ndOrder : public BoundaryOpWithApply &args, const std::map &keywords) override; - static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); - static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); - static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)); - static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)); + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; @@ -98,10 +98,10 @@ class BoundaryDirichlet_O5 : public BoundaryOpWithApply { BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); - static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); - static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)); - static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)); + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; @@ -135,88 +135,91 @@ class BoundaryNeumann2 : public BoundaryOpWithApply { BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); - static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); - static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); - static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; /// Neumann boundary condition set half way between guard cell and grid cell at 2nd order accuracy -class BoundaryNeumann_2ndOrder : public BoundaryOpWithApply { +class BoundaryNeumann_2ndOrder : public BoundaryOpWithApply { public: - using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors + using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); - static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); - static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); - static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; // Neumann boundary condition set half way between guard cell and grid cell at 2nd order accuracy -class BoundaryNeumann : public BoundaryOpWithApply { +class BoundaryNeumann : public BoundaryOpWithApply { public: - using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors + using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric); - static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric); - static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); - static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; /// Neumann boundary condition set half way between guard cell and grid cell at 4th order accuracy -class BoundaryNeumann_O4 : public BoundaryOpWithApply { +class BoundaryNeumann_O4 : public BoundaryOpWithApply { public: - using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors + using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric); - static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric); - static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); - static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; /// Neumann boundary condition set half way between guard cell and grid cell at 4th order accuracy -class BoundaryNeumann_4thOrder : public BoundaryOpWithApply { +class BoundaryNeumann_4thOrder : public BoundaryOpWithApply { public: - using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors + using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric); - static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric); - static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); - static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; /// NeumannPar (zero-gradient) boundary condition on /// the variable / sqrt(g_22) -class BoundaryNeumannPar : public BoundaryOpWithApply { +class BoundaryNeumannPar : public BoundaryOp { public: - using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors + using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric); - static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric); - static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); - static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); - static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); - static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); + void apply(Field2D &f, BoutReal t = 0.) final { + applyTemplate(f, t); + } + void apply(Field3D &f, BoutReal t = 0.) final { + applyTemplate(f, t); + } + private: + template + void applyTemplate(T &f, BoutReal t); }; /// Robin (mix of Dirichlet and Neumann) @@ -234,7 +237,7 @@ class BoundaryRobin : public BoundaryOp { void apply(Field3D &f, BoutReal t = 0.) final { applyTemplate(f, t); } -private: + private: BoutReal aval, bval, gval; template @@ -248,10 +251,10 @@ class BoundaryConstGradient : public BoundaryOpWithApply BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); - static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); - static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); - static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; @@ -263,8 +266,8 @@ class BoundaryZeroLaplace : public BoundaryOp { BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - void apply(Field2D &f, BoutReal UNUSED(t)) final; - void apply(Field3D &f, BoutReal UNUSED(t)) final; + void apply(Field2D &f, BoutReal t) final; + void apply(Field3D &f, BoutReal t) final; }; /// Zero Laplacian @@ -309,8 +312,8 @@ class BoundaryFree : public BoundaryOp { BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - void apply(Field2D &f, BoutReal UNUSED(t)) final; - void apply(Field3D &f, BoutReal UNUSED(t)) final; + void apply(Field2D &f, BoutReal t) final; + void apply(Field3D &f, BoutReal t) final; void apply_ddt(Field2D &f) final; void apply_ddt(Field3D &f) final; @@ -326,10 +329,10 @@ public: BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); - static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); - static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); - static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; @@ -340,10 +343,10 @@ public: BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric); - static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric); - static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); - static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; @@ -355,10 +358,10 @@ public: BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric); - static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric); - static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); - static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; @@ -369,10 +372,10 @@ public: BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; - static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric); - static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric); - static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); - static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)); + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; diff --git a/src/mesh/boundary_standard.cxx b/src/mesh/boundary_standard.cxx index 9dbc299e06..0138c9c4ce 100644 --- a/src/mesh/boundary_standard.cxx +++ b/src/mesh/boundary_standard.cxx @@ -174,9 +174,9 @@ namespace { // Included here so it's in the same 'translation unit' as the implementations, // so will be instantiated for each 'Derived'. -template +template template -void BoundaryOpWithApply::applyTemplate(T &f,BoutReal t) { +void BoundaryOpWithApply::applyTemplate(T &f, BoutReal t) { // Convert the pointer to have the type of the final implementation class, so // we can use the single-point methods directly @@ -208,13 +208,20 @@ void BoundaryOpWithApply::applyTemplate(T &f,BoutReal t) { BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) // In the guard cell + localmesh->GlobalY(bndry->y - bndry->by) ); // the grid cell + BoutReal delta; + if (needs_delta) { + delta = bndry->bx*metric->dx(bndry->x, bndry->y) + bndry->by*metric->dy(bndry->x, bndry->y); + } else { + delta = 0.; + } + for(int z=0; zGlobalZ(z); if (fg) { val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); } - Derived::applyAtPoint(f, val, bndry->x, bndry->bx, bndry->y, bndry->by, z, metric); + Derived::applyAtPoint(f, val, bndry->x, bndry->bx, bndry->y, bndry->by, z, delta); // Need to set second guard cell, as may be used for interpolation or upwinding derivatives for (int i = 1; i < width; i++) { @@ -234,12 +241,19 @@ void BoundaryOpWithApply::applyTemplate(T &f,BoutReal t) { + localmesh->GlobalX(bndry->x - bndry->bx) ); BoutReal ynorm = localmesh->GlobalY(bndry->y); + BoutReal delta; + if (needs_delta) { + delta = bndry->bx*metric->dx(bndry->x, bndry->y) + bndry->by*metric->dy(bndry->x, bndry->y); + } else { + delta = 0.; + } + for(int z=0; zGlobalZ(z); if (fg) { val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); } - Derived::applyAtPointStaggered(f, val, bndry->x, bndry->bx, bndry->y, 0, z, metric); + Derived::applyAtPointStaggered(f, val, bndry->x, bndry->bx, bndry->y, 0, z, delta); // Need to set second guard cell, as may be used for interpolation or upwinding derivatives for (int i = 1; i < width; i++) { @@ -256,13 +270,20 @@ void BoundaryOpWithApply::applyTemplate(T &f,BoutReal t) { + localmesh->GlobalX(bndry->x - bndry->bx) ); BoutReal ynorm = localmesh->GlobalY(bndry->y); + BoutReal delta; + if (needs_delta) { + delta = bndry->bx*metric->dx(bndry->x + 1, bndry->y) + bndry->by*metric->dy(bndry->x + 1, bndry->y); + } else { + delta = 0.; + } + for(int z=0; zGlobalZ(z); if (fg) { val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); } // Set one point inwards - Derived::applyAtPointStaggered(f, val, bndry->x + 1, bndry->bx, bndry->y, 0, z, metric); + Derived::applyAtPointStaggered(f, val, bndry->x + 1, bndry->bx, bndry->y, 0, z, delta); // Need to set second and third guard cells, as may be used for interpolation or upwinding derivatives for (int i = 0; i < width; i++) { @@ -279,12 +300,19 @@ void BoundaryOpWithApply::applyTemplate(T &f,BoutReal t) { 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; + if (needs_delta) { + delta = bndry->bx*metric->dx(bndry->x, bndry->y) + bndry->by*metric->dy(bndry->x, bndry->y); + } else { + delta = 0.; + } + for(int z=0; zGlobalZ(z); if (fg) { val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); } - Derived::applyAtPoint(f, val, bndry->x, 0, bndry->y, bndry->by, z, metric); + Derived::applyAtPoint(f, val, bndry->x, 0, bndry->y, bndry->by, z, delta); // Need to set second guard cell, as may be used for interpolation or upwinding derivatives for(int i=1;i::applyTemplate(T &f,BoutReal t) { 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) ); + + BoutReal delta; + if (needs_delta) { + delta = bndry->bx*metric->dx(bndry->x, bndry->y) + bndry->by*metric->dy(bndry->x, bndry->y); + } else { + delta = 0.; + } + for(int z=0; zGlobalZ(z); if (fg) { val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); } - Derived::applyAtPointStaggered(f, val, bndry->x, 0, bndry->y, bndry->by, z, metric); + Derived::applyAtPointStaggered(f, val, bndry->x, 0, bndry->y, bndry->by, z, delta); // Need to set second guard cell, as may be used for interpolation or upwinding derivatives for(int i=1;i::applyTemplate(T &f,BoutReal t) { BoutReal xnorm = localmesh->GlobalX(bndry->x); BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) + localmesh->GlobalY(bndry->y - bndry->by) ); + BoutReal delta; + if (needs_delta) { + delta = bndry->bx*metric->dx(bndry->x, bndry->y + 1) + bndry->by*metric->dy(bndry->x, bndry->y + 1); + } else { + delta = 0.; + } + for(int z=0; zGlobalZ(z); if (fg) { val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); } - Derived::applyAtPointStaggered(f, val, bndry->x, 0, bndry->y+1, bndry->by, z, metric); + Derived::applyAtPointStaggered(f, val, bndry->x, 0, bndry->y+1, bndry->by, z, delta); // Need to set second guard cell, as may be used for interpolation or upwinding derivatives for(int i=0;i::applyTemplate(T &f,BoutReal t) { 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; + if (needs_delta) { + delta = bndry->bx*metric->dx(bndry->x, bndry->y) + bndry->by*metric->dy(bndry->x, bndry->y); + } else { + delta = 0.; + } + for(int z=0; zGlobalZ(z); if (fg) { val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); } - Derived::applyAtPoint(f, val, bndry->x, bndry->bx, bndry->y, 0, z, metric); + Derived::applyAtPoint(f, val, bndry->x, bndry->bx, bndry->y, 0, z, delta); // Need to set second guard cell, as may be used for interpolation or upwinding derivatives for(int i=1;i::applyTemplate(T &f,BoutReal t) { BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) // In the guard cell + localmesh->GlobalY(bndry->y - bndry->by) ); // the grid cell + BoutReal delta; + if (needs_delta) { + delta = bndry->bx*metric->dx(bndry->x, bndry->y) + bndry->by*metric->dy(bndry->x, bndry->y); + } else { + delta = 0.; + } + for(int z=0; zgenerate should be periodic in z BoutReal znorm = 0.5*( localmesh->GlobalZ(z) + localmesh->GlobalZ(z - 1) ); // znorm is shifted by half a grid point because it is staggered if (fg) { val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); } - Derived::applyAtPoint(f, val, bndry->x, bndry->bx, bndry->y, bndry->by, z, metric); + Derived::applyAtPoint(f, val, bndry->x, bndry->bx, bndry->y, bndry->by, z, delta); // Need to set second guard cell, as may be used for interpolation or upwinding derivatives for (int i = 1; i < width; i++) { @@ -666,17 +724,17 @@ BoundaryOp* BoundaryDirichlet_O3::clone(BoundaryRegion *region, const list(region, args, keywords); } -void BoundaryDirichlet_O3::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { +void BoundaryDirichlet_O3::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { f(x, y, z) = (8./3)*val - 2.*f(x - bx, y - by, z) + f(x - 2*bx, y - 2*by, z)/3.; } -void BoundaryDirichlet_O3::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { +void BoundaryDirichlet_O3::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { f(x, y, z) = (8./3)*val - 2.*f(x - bx, y - by, z) + f(x - 2*bx, y - 2*by, z)/3.; } -void BoundaryDirichlet_O3::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) { +void BoundaryDirichlet_O3::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { f(x, y, z) = val; } -void BoundaryDirichlet_O3::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) { +void BoundaryDirichlet_O3::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { f(x, y, z) = val; } @@ -695,17 +753,17 @@ BoundaryOp* BoundaryDirichlet_O4::clone(BoundaryRegion *region, const list(region, args, keywords); } -void BoundaryDirichlet_O4::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { +void BoundaryDirichlet_O4::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { f(x, y, z) = (16./5)*val - 3.*f(x - bx, y - by, z) + f(x - 2*bx, y - 2*by, z) - (1./5)*f(x - 3*bx, y - 3*by, z); } -void BoundaryDirichlet_O4::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { +void BoundaryDirichlet_O4::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { f(x, y, z) = (16./5)*val - 3.*f(x - bx, y - by, z) + f(x - 2*bx, y - 2*by, z) - (1./5)*f(x - 3*bx, y - 3*by, z); } -void BoundaryDirichlet_O4::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) { +void BoundaryDirichlet_O4::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { f(x, y, z) = val; } -void BoundaryDirichlet_O4::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) { +void BoundaryDirichlet_O4::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { f(x, y, z) = val; } @@ -723,10 +781,10 @@ BoundaryOp* BoundaryDirichlet_smooth::clone(BoundaryRegion *region, const list(region, args, keywords); } -void BoundaryDirichlet_smooth::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { +void BoundaryDirichlet_smooth::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { f(x, y, z) = 5./3.*val - 0.5*f(x - bx, y - by, z) - 1./6.*f(x - 2*bx, y - 2*by, z); } -void BoundaryDirichlet_smooth::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { +void BoundaryDirichlet_smooth::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { // Dirichlet bc using val and first grid point would be // fb = 2*val - f0 // using val and second grid point would be @@ -736,10 +794,10 @@ void BoundaryDirichlet_smooth::applyAtPoint(Field3D &f, BoutReal val, int x, int f(x, y, z) = 5./3.*val - 0.5*f(x - bx, y - by, z) - 1./6.*f(x - 2*bx, y - 2*by, z); } -void BoundaryDirichlet_smooth::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) { +void BoundaryDirichlet_smooth::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { f(x, y, z) = val; } -void BoundaryDirichlet_smooth::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) { +void BoundaryDirichlet_smooth::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { f(x, y, z) = val; } @@ -761,17 +819,17 @@ BoundaryOp* BoundaryDirichlet_2ndOrder::clone(BoundaryRegion *region, const list // 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 -void BoundaryDirichlet_2ndOrder::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { +void BoundaryDirichlet_2ndOrder::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { f(x, y, z) = 8./3.*val - 2.*f(x - bx, y - by, z) + 1./3.*f(x - 2*bx, y - 2*by, z); } -void BoundaryDirichlet_2ndOrder::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { +void BoundaryDirichlet_2ndOrder::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { f(x, y, z) = 8./3.*val - 2.*f(x - bx, y - by, z) + 1./3.*f(x - 2*bx, y - 2*by, z); } -void BoundaryDirichlet_2ndOrder::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) { +void BoundaryDirichlet_2ndOrder::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { f(x, y, z) = val; } -void BoundaryDirichlet_2ndOrder::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) { +void BoundaryDirichlet_2ndOrder::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { f(x, y, z) = val; } @@ -789,17 +847,17 @@ BoundaryOp* BoundaryDirichlet_O5::clone(BoundaryRegion *region, const list(region, args, keywords); } -void BoundaryDirichlet_O5::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { +void BoundaryDirichlet_O5::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { f(x, y, z) = 128./35.*val - 4.*f(x - bx, y - by, z) + 2.*f(x - 2*bx, y - 2*by, z) - 4./5.*f(x - 3*bx, y - 3*by, z) + 1./7.*f(x - 4*bx, y - 4*by, z); } -void BoundaryDirichlet_O5::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { +void BoundaryDirichlet_O5::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { f(x, y, z) = 128./35.*val - 4.*f(x - bx, y - by, z) + 2.*f(x - 2*bx, y - 2*by, z) - 4./5.*f(x - 3*bx, y - 3*by, z) + 1./7.*f(x - 4*bx, y - 4*by, z); } -void BoundaryDirichlet_O5::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) { +void BoundaryDirichlet_O5::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { f(x, y, z) = val; } -void BoundaryDirichlet_O5::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, Coordinates* UNUSED(metric)) { +void BoundaryDirichlet_O5::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { f(x, y, z) = val; } @@ -888,17 +946,17 @@ BoundaryOp* BoundaryNeumann2::clone(BoundaryRegion *region, const list & return boundaryCloneNoArguments(region, args, keywords); } -void BoundaryNeumann2::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { +void BoundaryNeumann2::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { f(x, y, z) = (4.*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z))/3.; } -void BoundaryNeumann2::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { +void BoundaryNeumann2::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { f(x, y, z) = (4.*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z))/3.; } -void BoundaryNeumann2::applyAtPointStaggered(Field2D &UNUSED(f), BoutReal UNUSED(val), int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), Coordinates* UNUSED(metric)) { +void BoundaryNeumann2::applyAtPointStaggered(Field2D &UNUSED(f), BoutReal UNUSED(val), int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), BoutReal UNUSED(delta)) { throw BoutException("BoundaryNeumann2 not implemented for staggered grids"); } -void BoundaryNeumann2::applyAtPointStaggered(Field3D &UNUSED(f), BoutReal UNUSED(val), int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), Coordinates* UNUSED(metric)) { +void BoundaryNeumann2::applyAtPointStaggered(Field3D &UNUSED(f), BoutReal UNUSED(val), int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), BoutReal UNUSED(delta)) { throw BoutException("BoundaryNeumann2 not implemented for staggered grids"); } @@ -918,21 +976,17 @@ BoundaryOp* BoundaryNeumann_2ndOrder::clone(BoundaryRegion *region, const list(region, args, keywords); } -void BoundaryNeumann_2ndOrder::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { - BoutReal delta = bx*metric->dx(x, y) + by*metric->dy(x, y); +void BoundaryNeumann_2ndOrder::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { f(x, y, z) = f(x - bx, y - by, z) + val*delta; } -void BoundaryNeumann_2ndOrder::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { - BoutReal delta = bx*metric->dx(x, y) + by*metric->dy(x, y); +void BoundaryNeumann_2ndOrder::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { f(x, y, z) = f(x - bx, y - by, z) + val*delta; } -void BoundaryNeumann_2ndOrder::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { - BoutReal delta = bx*metric->dx(x, y) + by*metric->dy(x, y); +void BoundaryNeumann_2ndOrder::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { f(x, y, z) = (4.*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z) + 2.*delta*val)/3.; } -void BoundaryNeumann_2ndOrder::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { - BoutReal delta = bx*metric->dx(x, y) + by*metric->dy(x, y); +void BoundaryNeumann_2ndOrder::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { f(x, y, z) = (4.*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z) + 2.*delta*val)/3.; } @@ -951,23 +1005,19 @@ BoundaryOp* BoundaryNeumann::clone(BoundaryRegion *region, const list &a return boundaryClone(region, args, keywords); } -void BoundaryNeumann::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { - BoutReal delta = bx*metric->dx(x, y) + by*metric->dy(x, y); +void BoundaryNeumann::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { f(x, y, z) = f(x - bx, y - by, z) + delta*val; } -void BoundaryNeumann::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { - BoutReal delta = bx*metric->dx(x, y) + by*metric->dy(x, y); +void BoundaryNeumann::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { f(x, y, z) = f(x - bx, y - by, z) + delta*val; } // For staggered case need to apply slightly differently Use one-sided // differencing. Cell is now on the boundary, so use one-sided differencing -void BoundaryNeumann::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { - BoutReal delta = bx*metric->dx(x, y) + by*metric->dy(x, y); +void BoundaryNeumann::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { f(x, y, z) = (4.*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z) + 2.*delta*val)/3.; } -void BoundaryNeumann::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { - BoutReal delta = bx*metric->dx(x, y) + by*metric->dy(x, y); +void BoundaryNeumann::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { f(x, y, z) = (4.*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z) + 2.*delta*val)/3.; } @@ -987,27 +1037,23 @@ BoundaryOp* BoundaryNeumann_O4::clone(BoundaryRegion *region, const list return boundaryClone(region, args, keywords); } -void BoundaryNeumann_O4::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { - BoutReal delta = bx*metric->dx(x, y) + by*metric->dy(x, y); +void BoundaryNeumann_O4::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { f(x, y, z) = 12.*delta*val/11. + ( 17.*f(x - bx, y - by, z) + 9.*f(x - 2*bx, y - 2*by, z) - 5.*f(x - 3*bx, y - 3*by, z) + f(x - 4*bx, y - 4*by, z))/22.; } -void BoundaryNeumann_O4::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { - BoutReal delta = bx*metric->dx(x, y) + by*metric->dy(x, y); +void BoundaryNeumann_O4::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { f(x, y, z) = 12.*delta*val/11. + ( 17.*f(x - bx, y - by, z) + 9.*f(x - 2*bx, y - 2*by, z) - 5.*f(x - 3*bx, y - 3*by, z) + f(x - 4*bx, y - 4*by, z))/22.; } -void BoundaryNeumann_O4::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { - BoutReal delta = bx*metric->dx(x, y) + by*metric->dy(x, y); +void BoundaryNeumann_O4::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { f(x, y, z) = 12./25.*(delta*val + 4.*f(x - bx, y - by, z) - 3.*f(x - 2*bx, y - 2*by, z) + 4./3.*f(x - 3*bx, y - 3*by, z) - 1./4.*f(x - 4*bx, y - 4*by, z)); } -void BoundaryNeumann_O4::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { - BoutReal delta = bx*metric->dx(x, y) + by*metric->dy(x, y); +void BoundaryNeumann_O4::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { f(x, y, z) = 12./25.*(delta*val + 4.*f(x - bx, y - by, z) - 3.*f(x - 2*bx, y - 2*by, z) + 4./3.*f(x - 3*bx, y - 3*by, z) - 1./4.*f(x - 4*bx, y - 4*by, z)); @@ -1027,19 +1073,17 @@ BoundaryOp* BoundaryNeumann_4thOrder::clone(BoundaryRegion *region, const list(region, args, keywords); } -void BoundaryNeumann_4thOrder::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { - BoutReal delta = -(bx*metric->dx(x, y) + by*metric->dy(x, y)); +void BoundaryNeumann_4thOrder::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { f(x, y, z) = 12.*delta/11.*val + 17./22.*f(x - bx, y - by, z) + 9./22.*f(x - 2*bx, y - 2*by, z) - 5./22.*f(x - 3*bx, y - 3*by, z) + 1./22.*f(x - 4*bx, y - 4*by, z); } -void BoundaryNeumann_4thOrder::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, Coordinates* metric) { - BoutReal delta = -(bx*metric->dx(x, y) + by*metric->dy(x, y)); +void BoundaryNeumann_4thOrder::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { f(x, y, z) = 12.*delta/11.*val + 17./22.*f(x - bx, y - by, z) + 9./22.*f(x - 2*bx, y - 2*by, z) - 5./22.*f(x - 3*bx, y - 3*by, z) + 1./22.*f(x - 4*bx, y - 4*by, z); } -void BoundaryNeumann_4thOrder::applyAtPointStaggered(Field2D &UNUSED(f), BoutReal UNUSED(val), int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), Coordinates* UNUSED(metric)) { +void BoundaryNeumann_4thOrder::applyAtPointStaggered(Field2D &UNUSED(f), BoutReal UNUSED(val), int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), BoutReal UNUSED(delta)) { throw BoutException("BoundaryNeumann_4thOrder is not implemented for staggered grids."); } -void BoundaryNeumann_4thOrder::applyAtPointStaggered(Field3D &UNUSED(f), BoutReal UNUSED(val), int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), Coordinates* UNUSED(metric)) { +void BoundaryNeumann_4thOrder::applyAtPointStaggered(Field3D &UNUSED(f), BoutReal UNUSED(val), int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), BoutReal UNUSED(delta)) { throw BoutException("BoundaryNeumann_4thOrder is not implemented for staggered grids."); } @@ -1065,27 +1109,13 @@ BoundaryOp* BoundaryNeumannPar::clone(BoundaryRegion *region, const list return boundaryCloneNoArguments(region, args, keywords); } -void BoundaryNeumannPar::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* metric) { - // For each element, set equal to the next point in - f(x, y, z) = f(x - bx, y - by, z)*sqrt(metric->g_22(x, y)/metric->g_22(x - bx, y - by)); -} -void BoundaryNeumannPar::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* metric) { - // For each element, set equal to the next point in - f(x, y, z) = f(x - bx, y - by, z)*sqrt(metric->g_22(x, y)/metric->g_22(x - bx, y - by)); -} - -void BoundaryNeumannPar::applyAtPointStaggered(Field2D &UNUSED(f), BoutReal UNUSED(val), int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), Coordinates* UNUSED(metric)) { - throw BoutException("BoundaryNeumannPar is not implemented for staggered grids."); -} -void BoundaryNeumannPar::applyAtPointStaggered(Field3D &UNUSED(f), BoutReal UNUSED(val), int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), Coordinates* UNUSED(metric)) { - throw BoutException("BoundaryNeumannPar is not implemented for staggered grids."); -} - -void BoundaryNeumannPar::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { - extrapolate2nd(f, x, bx, y, by, z); -} -void BoundaryNeumannPar::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { - extrapolate2nd(f, x, bx, y, by, z); +template +void BoundaryNeumannPar::applyTemplate(T &f, BoutReal UNUSED(t)) { + ASSERT1(f.getLocation() == CELL_CENTRE); // BoundaryNeumannPar not implemented for staggered fields + Coordinates *metric = f.getCoordinates(); + for(bndry->first(); !bndry->isDone(); bndry->next()) + 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)); } /////////////////////////////////////////////////////////////// @@ -1150,17 +1180,17 @@ BoundaryOp* BoundaryConstGradient::clone(BoundaryRegion *region, const list(region, args, keywords); } -void BoundaryConstGradient::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { +void BoundaryConstGradient::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { f(x, y, z) = 2.*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z); } -void BoundaryConstGradient::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { +void BoundaryConstGradient::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { f(x, y, z) = 2.*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z); } -void BoundaryConstGradient::applyAtPointStaggered(Field2D &UNUSED(f), BoutReal UNUSED(val), int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), Coordinates* UNUSED(metric)) { +void BoundaryConstGradient::applyAtPointStaggered(Field2D &UNUSED(f), BoutReal UNUSED(val), int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), BoutReal UNUSED(delta)) { throw BoutException("BoundaryConstGradient is not implemented for staggered grids."); } -void BoundaryConstGradient::applyAtPointStaggered(Field3D &UNUSED(f), BoutReal UNUSED(val), int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), Coordinates* UNUSED(metric)) { +void BoundaryConstGradient::applyAtPointStaggered(Field3D &UNUSED(f), BoutReal UNUSED(val), int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), BoutReal UNUSED(delta)) { throw BoutException("BoundaryConstGradient is not implemented for staggered grids."); } @@ -1552,17 +1582,17 @@ BoundaryOp* BoundaryFree_O2::clone(BoundaryRegion *region, const list &a return boundaryCloneNoArguments(region, args, keywords); } -void BoundaryFree_O2::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { +void BoundaryFree_O2::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate2nd(f, x, bx, y, by, z); } -void BoundaryFree_O2::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { +void BoundaryFree_O2::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate2nd(f, x, bx, y, by, z); } -void BoundaryFree_O2::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { +void BoundaryFree_O2::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate2nd(f, x, bx, y, by, z); } -void BoundaryFree_O2::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { +void BoundaryFree_O2::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate2nd(f, x, bx, y, by, z); } @@ -1581,17 +1611,17 @@ BoundaryOp* BoundaryFree_O3::clone(BoundaryRegion *region, const list &a return boundaryCloneNoArguments(region, args, keywords); } -void BoundaryFree_O3::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { +void BoundaryFree_O3::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate3rd(f, x, bx, y, by, z); } -void BoundaryFree_O3::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { +void BoundaryFree_O3::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate3rd(f, x, bx, y, by, z); } -void BoundaryFree_O3::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { +void BoundaryFree_O3::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate3rd(f, x, bx, y, by, z); } -void BoundaryFree_O3::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { +void BoundaryFree_O3::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate3rd(f, x, bx, y, by, z); } @@ -1608,17 +1638,17 @@ BoundaryOp* BoundaryFree_O4::clone(BoundaryRegion *region, const list &a return boundaryCloneNoArguments(region, args, keywords); } -void BoundaryFree_O4::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { +void BoundaryFree_O4::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate4th(f, x, bx, y, by, z); } -void BoundaryFree_O4::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { +void BoundaryFree_O4::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate4th(f, x, bx, y, by, z); } -void BoundaryFree_O4::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { +void BoundaryFree_O4::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate4th(f, x, bx, y, by, z); } -void BoundaryFree_O4::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { +void BoundaryFree_O4::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate4th(f, x, bx, y, by, z); } @@ -1635,17 +1665,17 @@ BoundaryOp* BoundaryFree_O5::clone(BoundaryRegion *region, const list &a return boundaryCloneNoArguments(region, args, keywords); } -void BoundaryFree_O5::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { +void BoundaryFree_O5::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate5th(f, x, bx, y, by, z); } -void BoundaryFree_O5::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { +void BoundaryFree_O5::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate5th(f, x, bx, y, by, z); } -void BoundaryFree_O5::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { +void BoundaryFree_O5::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate5th(f, x, bx, y, by, z); } -void BoundaryFree_O5::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, Coordinates* UNUSED(metric)) { +void BoundaryFree_O5::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate5th(f, x, bx, y, by, z); } From 5fcc7df4b4f46e2f4c980328c360947dd3922ef9 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 31 Oct 2018 00:23:03 +0000 Subject: [PATCH 37/45] Speed up BoundaryOps Move 'if (fg)' condition outside loops in boundary ops Introduces some code duplication, but significantly decreases time to apply boundary ops. Only calculate xnorm/ynorm if FieldGenerator fg is set Add some inline keywords --- include/boundary_op.hxx | 9 +- include/boundary_standard.hxx | 12 +- src/mesh/boundary_standard.cxx | 1215 ++++++++++++++++++++------------ 3 files changed, 781 insertions(+), 455 deletions(-) diff --git a/include/boundary_op.hxx b/include/boundary_op.hxx index 4f38510773..b0b851bdd4 100644 --- a/include/boundary_op.hxx +++ b/include/boundary_op.hxx @@ -23,12 +23,12 @@ using std::list; class BoundaryOp { public: BoundaryOp(bool apply_ddt = false) : bndry(nullptr), apply_to_ddt(apply_ddt), - gen(nullptr), width(0) {} + val(0.), gen(nullptr), width(0) {} BoundaryOp(BoundaryRegion *region, int width_in = 0, bool apply_ddt = false) - : bndry(region), apply_to_ddt(apply_ddt), gen(nullptr), + : bndry(region), apply_to_ddt(apply_ddt), val(0.), gen(nullptr), width(width_in ? width_in : region->width) {} - BoundaryOp(BoundaryRegion *region, std::shared_ptr g, int width_in = 0) - : bndry(region), apply_to_ddt(false), gen(std::move(g)), + BoundaryOp(BoundaryRegion *region, BoutReal val_in, std::shared_ptr g, int width_in = 0) + : bndry(region), apply_to_ddt(false), val(val_in), gen(std::move(g)), width(width_in ? width_in : region->width) {} virtual ~BoundaryOp() {} @@ -69,6 +69,7 @@ public: BoundaryRegion *bndry; const bool apply_to_ddt; // True if this boundary condition should be applied on the time derivatives, false if it should be applied to the field values protected: + const BoutReal val; // constant value for boundary condition std::shared_ptr gen; // Generator const int width; // boundary width, stored in case we change it from the default }; diff --git a/include/boundary_standard.hxx b/include/boundary_standard.hxx index f4900f012f..bbeb8ed708 100644 --- a/include/boundary_standard.hxx +++ b/include/boundary_standard.hxx @@ -109,9 +109,9 @@ class BoundaryDirichlet_O5 : public BoundaryOpWithApply { /// Neumann (zero-gradient) boundary condition for non-orthogonal meshes class BoundaryNeumann_NonOrthogonal : public BoundaryOp { public: - BoundaryNeumann_NonOrthogonal(): val(0.) {} - BoundaryNeumann_NonOrthogonal(BoutReal setval ): val(setval) {} - BoundaryNeumann_NonOrthogonal(BoundaryRegion *region, BoutReal setval=0.):BoundaryOp(region),val(setval) { } + BoundaryNeumann_NonOrthogonal() {} + BoundaryNeumann_NonOrthogonal(BoutReal setval): BoundaryOp(nullptr, setval, nullptr, 0) {} + BoundaryNeumann_NonOrthogonal(BoundaryRegion *region, BoutReal setval=0.):BoundaryOp(region, setval, nullptr, 0) {} BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; @@ -122,8 +122,6 @@ class BoundaryNeumann_NonOrthogonal : public BoundaryOp { applyTemplate(f, t); } private: - BoutReal val; - template void applyTemplate(T &f, BoutReal t); }; @@ -238,7 +236,7 @@ class BoundaryRobin : public BoundaryOp { applyTemplate(f, t); } private: - BoutReal aval, bval, gval; + const BoutReal aval, bval, gval; template void applyTemplate(T &f, BoutReal t); @@ -317,8 +315,6 @@ class BoundaryFree : public BoundaryOp { void apply_ddt(Field2D &f) final; void apply_ddt(Field3D &f) final; - private: - BoutReal val; }; // L. Easy diff --git a/src/mesh/boundary_standard.cxx b/src/mesh/boundary_standard.cxx index 0138c9c4ce..d0c6402082 100644 --- a/src/mesh/boundary_standard.cxx +++ b/src/mesh/boundary_standard.cxx @@ -133,9 +133,16 @@ namespace { verifyNumPoints(region, numpoints); std::shared_ptr newgen = nullptr; + BoutReal val = 0.; if (!args.empty()) { - // First argument should be an expression - newgen = FieldFactory::get()->parse(args.front()); + // First argument should be a value or expression + std::string expr = args.front(); + try { + val = stringToReal(expr); + } catch (const BoutException&) { + val = 0.; + newgen = FieldFactory::get()->parse(expr); + } } int width = region->width; for (const auto &it : keywords) { @@ -145,7 +152,7 @@ namespace { throw BoutException("Unrecognized boundary condition keyword %s for %s boundary", it.first.c_str(), region->label.c_str()); } } - return new T(region, newgen, width); + return new T(region, val, newgen, width); } template @@ -185,120 +192,237 @@ void BoundaryOpWithApply::applyTemplate(T &f, BoutReal t) Mesh* localmesh = f.getMesh(); Coordinates* metric = f.getCoordinates(); - // Check for staggered grids CELL_LOC loc = f.getLocation(); bndry->first(); + int nz = f.getNz(); + // Decide which generator to use std::shared_ptr fg = gen; if (!fg) { fg = f.getBndryGenerator(bndry->location); } - BoutReal val = 0.0; + if (fg) { + BoutReal generated_val = 0.0; - if (loc == CELL_CENTRE) { - // no staggering - 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 + if (loc == CELL_CENTRE) { + // no staggering + 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 - BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) // In the guard cell - + localmesh->GlobalY(bndry->y - bndry->by) ); // 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; - if (needs_delta) { - delta = bndry->bx*metric->dx(bndry->x, bndry->y) + bndry->by*metric->dy(bndry->x, bndry->y); - } else { - delta = 0.; - } + BoutReal delta; + if (needs_delta) { + delta = bndry->bx*metric->dx(bndry->x, bndry->y) + bndry->by*metric->dy(bndry->x, bndry->y); + } else { + delta = 0.; + } - for(int z=0; zGlobalZ(z); - if (fg) { - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + for(int z=0; zgenerate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + + Derived::applyAtPoint(f, generated_val, bndry->x, bndry->bx, bndry->y, bndry->by, z, delta); } - Derived::applyAtPoint(f, val, bndry->x, bndry->bx, bndry->y, bndry->by, z, delta); // Need to set second guard cell, as may be used for interpolation or upwinding derivatives for (int i = 1; i < width; i++) { int x = bndry->x + i*bndry->bx; int y = bndry->y + i*bndry->by; - Derived::extrapolateFurther(f, x, bndry->bx, y, bndry->by, z); + for(int z=0; zbx, y, bndry->by, z); + } } } } - } - else 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); + else 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); + + BoutReal delta; + if (needs_delta) { + delta = bndry->bx*metric->dx(bndry->x, bndry->y) + bndry->by*metric->dy(bndry->x, bndry->y); + } else { + delta = 0.; + } - BoutReal delta; - if (needs_delta) { - delta = bndry->bx*metric->dx(bndry->x, bndry->y) + bndry->by*metric->dy(bndry->x, bndry->y); - } else { - delta = 0.; + for(int z=0; zgenerate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + + Derived::applyAtPointStaggered(f, generated_val, bndry->x, bndry->bx, bndry->y, 0, z, delta); + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for (int i = 1; i < width; i++) { + int x = bndry->x + i*bndry->bx; + Derived::extrapolateFurther(f, x, bndry->bx, bndry->y, 0, z); + } + } } + } else 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); + + BoutReal delta; + if (needs_delta) { + delta = bndry->bx*metric->dx(bndry->x + 1, bndry->y) + bndry->by*metric->dy(bndry->x + 1, bndry->y); + } else { + delta = 0.; + } + + for(int z=0; zgenerate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + + // Set one point inwards + Derived::applyAtPointStaggered(f, generated_val, bndry->x + 1, bndry->bx, bndry->y, 0, z, delta); - for(int z=0; zGlobalZ(z); - if (fg) { - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + // Need to set second and third guard cells, as may be used for interpolation or upwinding derivatives + for (int i = 0; i < width; i++) { + int x = bndry->x + i*bndry->bx; + Derived::extrapolateFurther(f, x, bndry->bx, bndry->y, 0, z); + } + } + } + } else if (bndry->by !=0) { + // y boundaries + for(; !bndry->isDone(); bndry->next1d()) { + // x norm is shifted bndry->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; + if (needs_delta) { + delta = bndry->bx*metric->dx(bndry->x, bndry->y) + bndry->by*metric->dy(bndry->x, bndry->y); + } else { + delta = 0.; } - Derived::applyAtPointStaggered(f, val, bndry->x, bndry->bx, bndry->y, 0, z, delta); - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for (int i = 1; i < width; i++) { - int x = bndry->x + i*bndry->bx; - Derived::extrapolateFurther(f, x, bndry->bx, bndry->y, 0, z); + for(int z=0; zgenerate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + + Derived::applyAtPoint(f, generated_val, bndry->x, 0, bndry->y, bndry->by, z, delta); + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=1;iy + i*bndry->by; + Derived::extrapolateFurther(f, bndry->x, 0, y, bndry->by, z); + } } } } - } else if (bndry->bx < 0) { - // Inner x boundary. Set one point inwards - for(; !bndry->isDone(); bndry->next1d()) { + } 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)); + + BoutReal delta; + if (needs_delta) { + delta = bndry->bx*metric->dx(bndry->x, bndry->y) + bndry->by*metric->dy(bndry->x, bndry->y); + } else { + delta = 0.; + } - BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) - + localmesh->GlobalX(bndry->x - bndry->bx) ); - BoutReal ynorm = localmesh->GlobalY(bndry->y); + for(int z=0; zgenerate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); - BoutReal delta; - if (needs_delta) { - delta = bndry->bx*metric->dx(bndry->x + 1, bndry->y) + bndry->by*metric->dy(bndry->x + 1, bndry->y); - } else { - delta = 0.; + Derived::applyAtPointStaggered(f, generated_val, bndry->x, 0, bndry->y, bndry->by, z, delta); + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=1;iy + i*bndry->by; + Derived::extrapolateFurther(f, bndry->x, 0, y, bndry->by, z); + } + } } + } else 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)); + + BoutReal delta; + if (needs_delta) { + delta = bndry->bx*metric->dx(bndry->x, bndry->y + 1) + bndry->by*metric->dy(bndry->x, bndry->y + 1); + } else { + delta = 0.; + } - for(int z=0; zGlobalZ(z); - if (fg) { - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + for(int z=0; zgenerate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + + Derived::applyAtPointStaggered(f, generated_val, bndry->x, 0, bndry->y+1, bndry->by, z, delta); + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=0;iy + i*bndry->by; + Derived::extrapolateFurther(f, bndry->x, 0, y, bndry->by, z); + } + } + } + } else 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; + if (needs_delta) { + delta = bndry->bx*metric->dx(bndry->x, bndry->y) + bndry->by*metric->dy(bndry->x, bndry->y); + } else { + delta = 0.; } - // Set one point inwards - Derived::applyAtPointStaggered(f, val, bndry->x + 1, bndry->bx, bndry->y, 0, z, delta); - // Need to set second and third guard cells, as may be used for interpolation or upwinding derivatives - for (int i = 0; i < width; i++) { - int x = bndry->x + i*bndry->bx; - Derived::extrapolateFurther(f, x, bndry->bx, bndry->y, 0, z); + for(int z=0; zgenerate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + + Derived::applyAtPoint(f, generated_val, bndry->x, bndry->bx, bndry->y, 0, z, delta); + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=1;ix + i*bndry->bx; + Derived::extrapolateFurther(f, x, bndry->bx, bndry->y, 0, z); + } } } } - } else if (bndry->by !=0) { - // y boundaries + } else if (loc == CELL_ZLOW) { + // Staggered in Z. Note there are no z-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) ); + // 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; if (needs_delta) { @@ -307,30 +431,26 @@ void BoundaryOpWithApply::applyTemplate(T &f, BoutReal t) delta = 0.; } - for(int z=0; zGlobalZ(z); - if (fg) { - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); - } - Derived::applyAtPoint(f, val, bndry->x, 0, bndry->y, bndry->by, z, delta); + for(int z=0; zgenerate should be periodic in z + BoutReal znorm = (BoutReal(z) - 0.5)/BoutReal(nz); // znorm is shifted by half a grid point because it is staggered + generated_val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + + Derived::applyAtPoint(f, generated_val, bndry->x, bndry->bx, bndry->y, bndry->by, z, delta); // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=1;ix + i*bndry->bx; int y = bndry->y + i*bndry->by; - Derived::extrapolateFurther(f, bndry->x, 0, y, bndry->by, z); + Derived::extrapolateFurther(f, x, bndry->bx, y, bndry->by, z); } } } } - } else if (loc == CELL_YLOW) { - // Shifted in Y - if (bndry->by > 0) { - // Upper y boundary boundary + } else { + if (loc == CELL_CENTRE) { + // no staggering 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) ); - BoutReal delta; if (needs_delta) { delta = bndry->bx*metric->dx(bndry->x, bndry->y) + bndry->by*metric->dy(bndry->x, bndry->y); @@ -338,56 +458,151 @@ void BoundaryOpWithApply::applyTemplate(T &f, BoutReal t) delta = 0.; } - for(int z=0; zGlobalZ(z); - if (fg) { - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + for(int z=0; zx, bndry->bx, bndry->y, bndry->by, z, delta); + } + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for (int i = 1; i < width; i++) { + int x = bndry->x + i*bndry->bx; + int y = bndry->y + i*bndry->by; + for(int z=0; zbx, y, bndry->by, z); + } + } + } + } + else if (loc == CELL_XLOW) { + // field is shifted in X + if (bndry->bx > 0) { + // Outer x boundary + for(; !bndry->isDone(); bndry->next1d()) { + BoutReal delta; + if (needs_delta) { + delta = bndry->bx*metric->dx(bndry->x, bndry->y) + bndry->by*metric->dy(bndry->x, bndry->y); + } else { + delta = 0.; } - Derived::applyAtPointStaggered(f, val, bndry->x, 0, bndry->y, bndry->by, z, delta); - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=1;iy + i*bndry->by; - Derived::extrapolateFurther(f, bndry->x, 0, y, bndry->by, z); + for(int z=0; zx, bndry->bx, bndry->y, 0, z, delta); + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for (int i = 1; i < width; i++) { + int x = bndry->x + i*bndry->bx; + Derived::extrapolateFurther(f, x, bndry->bx, bndry->y, 0, z); + } + } + } + } else if (bndry->bx < 0) { + // Inner x boundary. Set one point inwards + for(; !bndry->isDone(); bndry->next1d()) { + BoutReal delta; + if (needs_delta) { + delta = bndry->bx*metric->dx(bndry->x + 1, bndry->y) + bndry->by*metric->dy(bndry->x + 1, bndry->y); + } else { + delta = 0.; + } + + for(int z=0; zx + 1, bndry->bx, bndry->y, 0, z, delta); + + // Need to set second and third guard cells, as may be used for interpolation or upwinding derivatives + for (int i = 0; i < width; i++) { + int x = bndry->x + i*bndry->bx; + Derived::extrapolateFurther(f, x, bndry->bx, bndry->y, 0, z); + } + } + } + } else if (bndry->by !=0) { + // y boundaries + for(; !bndry->isDone(); bndry->next1d()) { + BoutReal delta; + if (needs_delta) { + delta = bndry->bx*metric->dx(bndry->x, bndry->y) + bndry->by*metric->dy(bndry->x, bndry->y); + } else { + delta = 0.; + } + + for(int z=0; zx, 0, bndry->y, bndry->by, z, delta); + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=1;iy + i*bndry->by; + Derived::extrapolateFurther(f, bndry->x, 0, y, bndry->by, z); + } } } } - } else if (bndry->by < 0) { - // Lower y boundary. Set one point inwards - for(; !bndry->isDone(); bndry->next1d()) { + } else if (loc == CELL_YLOW) { + // Shifted in Y + if (bndry->by > 0) { + // Upper y boundary boundary + for(; !bndry->isDone(); bndry->next1d()) { + + BoutReal delta; + if (needs_delta) { + delta = bndry->bx*metric->dx(bndry->x, bndry->y) + bndry->by*metric->dy(bndry->x, bndry->y); + } else { + delta = 0.; + } - BoutReal xnorm = localmesh->GlobalX(bndry->x); - BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) + localmesh->GlobalY(bndry->y - bndry->by) ); + for(int z=0; zx, 0, bndry->y, bndry->by, z, delta); - BoutReal delta; - if (needs_delta) { - delta = bndry->bx*metric->dx(bndry->x, bndry->y + 1) + bndry->by*metric->dy(bndry->x, bndry->y + 1); - } else { - delta = 0.; + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=1;iy + i*bndry->by; + Derived::extrapolateFurther(f, bndry->x, 0, y, bndry->by, z); + } + } } + } else if (bndry->by < 0) { + // Lower y boundary. Set one point inwards + for(; !bndry->isDone(); bndry->next1d()) { + BoutReal delta; + if (needs_delta) { + delta = bndry->bx*metric->dx(bndry->x, bndry->y + 1) + bndry->by*metric->dy(bndry->x, bndry->y + 1); + } else { + delta = 0.; + } + + for(int z=0; zx, 0, bndry->y+1, bndry->by, z, delta); - for(int z=0; zGlobalZ(z); - if (fg) { - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=0;iy + i*bndry->by; + Derived::extrapolateFurther(f, bndry->x, 0, y, bndry->by, z); + } + } + } + } else if (bndry->bx != 0) { + // x boundaries + for(; !bndry->isDone(); bndry->next1d()) { + BoutReal delta; + if (needs_delta) { + delta = bndry->bx*metric->dx(bndry->x, bndry->y) + bndry->by*metric->dy(bndry->x, bndry->y); + } else { + delta = 0.; } - Derived::applyAtPointStaggered(f, val, bndry->x, 0, bndry->y+1, bndry->by, z, delta); - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=0;iy + i*bndry->by; - Derived::extrapolateFurther(f, bndry->x, 0, y, bndry->by, z); + for(int z=0; zx, bndry->bx, bndry->y, 0, z, delta); + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=1;ix + i*bndry->bx; + Derived::extrapolateFurther(f, x, bndry->bx, bndry->y, 0, z); + } } } } - } else if (bndry->bx != 0) { - // x boundaries + } else if (loc == CELL_ZLOW) { + // Staggered in Z. Note there are no z-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; if (needs_delta) { delta = bndry->bx*metric->dx(bndry->x, bndry->y) + bndry->by*metric->dy(bndry->x, bndry->y); @@ -395,55 +610,18 @@ void BoundaryOpWithApply::applyTemplate(T &f, BoutReal t) delta = 0.; } - for(int z=0; zGlobalZ(z); - if (fg) { - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); - } - - Derived::applyAtPoint(f, val, bndry->x, bndry->bx, bndry->y, 0, z, delta); + for(int z=0; zx, bndry->bx, bndry->y, bndry->by, z, delta); // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=1;ix + i*bndry->bx; - Derived::extrapolateFurther(f, x, bndry->bx, bndry->y, 0, z); + int y = bndry->y + i*bndry->by; + Derived::extrapolateFurther(f, x, bndry->bx, y, bndry->by, z); } } } } - } else if (loc == CELL_ZLOW) { - // Staggered in Z. Note there are no z-boundaries. - 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 - - BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) // In the guard cell - + localmesh->GlobalY(bndry->y - bndry->by) ); // the grid cell - - BoutReal delta; - if (needs_delta) { - delta = bndry->bx*metric->dx(bndry->x, bndry->y) + bndry->by*metric->dy(bndry->x, bndry->y); - } else { - delta = 0.; - } - - for(int z=0; zgenerate should be periodic in z - BoutReal znorm = 0.5*( localmesh->GlobalZ(z) + localmesh->GlobalZ(z - 1) ); // znorm is shifted by half a grid point because it is staggered - if (fg) { - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); - } - Derived::applyAtPoint(f, val, bndry->x, bndry->bx, bndry->y, bndry->by, z, delta); - - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for (int i = 1; i < width; i++) { - int x = bndry->x + i*bndry->bx; - int y = bndry->y + i*bndry->by; - Derived::extrapolateFurther(f, x, bndry->bx, y, bndry->by, z); - } - } - } } } @@ -470,211 +648,389 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal t) { bndry->first(); + int nz = f.getNz(); + // Decide which generator to use std::shared_ptr fg = gen; if (!fg) { fg = f.getBndryGenerator(bndry->location); } - BoutReal val = 0.0; - - if (loc == CELL_CENTRE) { - // Unstaggered case - 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 + if (fg) { + BoutReal generated_val = 0.; - BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) // In the guard cell - + localmesh->GlobalY(bndry->y - bndry->by) ); // the grid cell + if (loc == CELL_CENTRE) { + // Unstaggered case + 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 + + 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; zkgenerate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + + f(bndry->x,bndry->y,zk) = 2*generated_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 + // set the rest of the boundary cells also using + // extrapolation. Whilst this choice doesn't impact 2nd order + // methods it has been observed that with higher order + // methods, which actually use these points, the use of + // extrapolation can be unstable. For this reason we have + // commented out the below block and replaced it with the loop + // several lines below, which just sets all the rest of the + // boundary points to be the specified value. We've not + // removed the commented out code as we may wish to revisit + // this in the future, however it may be that this is + // eventually removed. It can be noted that we *don't* apply + // this treatment for other boundary treatments, + // i.e. elsewhere we tend to extrapolate. + + // // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + // for(int i=1;ix + 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); + // // 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; zkGlobalZ(zk); - if (fg) { - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + // This loop is our alternative approach to setting the rest of the boundary + // points. Instead of extrapolating we just use the generated values. This + // can help with the stability of higher order methods. + for (int i = 1; i < width; i++) { + // 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 = localmesh->GlobalX(xi); + ynorm = localmesh->GlobalY(yi); + for(int zk=0; zkgenerate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + + f(xi, yi, zk) = generated_val; + } } - 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 - // set the rest of the boundary cells also using - // extrapolation. Whilst this choice doesn't impact 2nd order - // methods it has been observed that with higher order - // methods, which actually use these points, the use of - // extrapolation can be unstable. For this reason we have - // commented out the below block and replaced it with the loop - // several lines below, which just sets all the rest of the - // boundary points to be the specified value. We've not - // removed the commented out code as we may wish to revisit - // this in the future, however it may be that this is - // eventually removed. It can be noted that we *don't* apply - // this treatment for other boundary treatments, - // i.e. elsewhere we tend to extrapolate. - - // // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - // for(int i=1;ix + 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); - // // 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); - - // } } - - // This loop is our alternative approach to setting the rest of the boundary - // points. Instead of extrapolating we just use the generated values. This - // can help with the stability of higher order methods. - for (int i = 1; i < width; i++) { - // 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 = localmesh->GlobalX(xi); - ynorm = localmesh->GlobalY(yi); - for(int zk=0; zkGlobalZ(zk); - if (fg) { - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + } else 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; zkgenerate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + + f(bndry->x,bndry->y, zk) = generated_val; + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=1;ix + 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 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; zkgenerate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + + f(bndry->x - bndry->bx, bndry->y, zk) = generated_val; + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=0;ix + 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 if (bndry->by !=0) { + // y boundaries + for(; !bndry->isDone(); bndry->next1d()) { + // x norm is shifted bndry->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; zkgenerate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + + f(bndry->x, bndry->y, zk) = 2*generated_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;ix ; + 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); + } } - f(xi, yi, zk) = val; } } - } - } else 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; zkGlobalZ(zk); - if (fg) { - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + } 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; zkgenerate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + + f(bndry->x, bndry->y, zk) = generated_val; + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=1;ix ; + 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); + } } - f(bndry->x,bndry->y, zk) = val; + } + } else 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) ); - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=1;ix + i*bndry->bx; - int yi = bndry->y ; + for(int zk=0; zkgenerate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + + f(bndry->x, bndry->y - bndry->by, zk) = generated_val; + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=0;ix ; + int yi = bndry->y + i*bndry->by; - f(xi, yi, zk) = 2*f(xi - bndry->bx, yi , zk) - f(xi- 2*bndry->bx, yi , zk); + f(xi, yi, zk) = 2*f(xi, yi - bndry->by, zk) - f(xi, yi - 2*bndry->by, zk); + } + } + } + } else 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; zkgenerate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + + f(bndry->x, bndry->y, zk) = 2*generated_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;ix + 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 if (bndry->bx < 0) { - // Inner x boundary. Set one point inwards + } else if (loc == CELL_ZLOW) { + // Staggered in Z. Note there are no z-boundaries. 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 - BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) - + localmesh->GlobalX(bndry->x - bndry->bx) ); - BoutReal ynorm = localmesh->GlobalY(bndry->y); + 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; zkGlobalZ(zk); - if (fg) { - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); - } - f(bndry->x - bndry->bx,bndry->y, zk) = val; + for(int zk=0; zkgenerate should be periodic in z + BoutReal znorm = (BoutReal(zk) - 0.5)/BoutReal(nz); // znorm is shifted by half a grid point because it is staggered + generated_val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + + f(bndry->x, bndry->y, zk) = 2*generated_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=0;ix + 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); + f(xi, yi, zk) = 2*f(xi - bndry->bx, yi , zk) - f(xi - 2*bndry->bx, yi, zk); } } } - } else if (bndry->by !=0) { - // y boundaries + } + } else { + if (loc == CELL_CENTRE) { + // Unstaggered case 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; zkGlobalZ(zk); - if (fg) { - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, 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;ix ; - int yi = bndry->y + i*bndry->by; + for(int zk=0; zkx, 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 + // set the rest of the boundary cells also using + // extrapolation. Whilst this choice doesn't impact 2nd order + // methods it has been observed that with higher order + // methods, which actually use these points, the use of + // extrapolation can be unstable. For this reason we have + // commented out the below block and replaced it with the loop + // several lines below, which just sets all the rest of the + // boundary points to be the specified value. We've not + // removed the commented out code as we may wish to revisit + // this in the future, however it may be that this is + // eventually removed. It can be noted that we *don't* apply + // this treatment for other boundary treatments, + // i.e. elsewhere we tend to extrapolate. + + // // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + // for(int i=1;ix + 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); + // // 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); + + // } + } - f(xi, yi, zk) = 2*f(xi, yi - bndry->by, zk) - f(xi, yi - 2*bndry->by, zk); + // This loop is our alternative approach to setting the rest of the boundary + // points. Instead of extrapolating we just use the generated values. This + // can help with the stability of higher order methods. + for (int i = 1; i < width; i++) { + // 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; + for(int zk=0; zkby > 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; zkGlobalZ(zk); - if (fg) { - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + } else 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; zkx, bndry->y, zk) = val; + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=1;ix + 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); + } } - 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;ix ; - 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); + } + } else if (bndry->bx < 0) { + // Inner x boundary. Set one point inwards + for(; !bndry->isDone(); bndry->next1d()) { + for(int zk=0; zkx - bndry->bx, bndry->y, zk) = val; + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=0;ix + 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 if (bndry->by !=0) { + // y boundaries + for(; !bndry->isDone(); bndry->next1d()) { + for(int zk=0; zkx, 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;ix ; + 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 (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; zkGlobalZ(zk); - if (fg) { - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + } else if (loc == CELL_YLOW) { + // Shifted in Y + if (bndry->by > 0) { + // Upper y boundary boundary + for(; !bndry->isDone(); bndry->next1d()) { + for(int zk=0; zkx, bndry->y, zk) = val; + + // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + for(int i=1;ix ; + 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); + } } - 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;ix ; - 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 (bndry->by < 0) { + // Lower y boundary. Set one point inwards + for(; !bndry->isDone(); bndry->next1d()) { + for(int zk=0; zkx, 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;ix ; + 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 (bndry->bx != 0) { + // x boundaries + for(; !bndry->isDone(); bndry->next1d()) { + for(int zk=0; zkx, 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;ix + 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 if (bndry->bx != 0) { - // x boundaries + } else if (loc == CELL_ZLOW) { + // Staggered in Z. Note there are no z-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; zkGlobalZ(zk); - if (fg) { - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); - } - - f(bndry->x,bndry->y,zk) = 2*val - f(bndry->x-bndry->bx, bndry->y-bndry->by, zk); + for(int zk=0; zkx, 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;iisDone(); 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 - - 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; zkgenerate should be periodic in z - BoutReal znorm = 0.5*( localmesh->GlobalZ(zk) + localmesh->GlobalZ(zk - 1) ); // znorm is shifted by half a grid point because it is staggered - if (fg) { - val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, 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;ix + 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); - } - } - } } } @@ -724,24 +1053,24 @@ BoundaryOp* BoundaryDirichlet_O3::clone(BoundaryRegion *region, const list(region, args, keywords); } -void BoundaryDirichlet_O3::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryDirichlet_O3::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { f(x, y, z) = (8./3)*val - 2.*f(x - bx, y - by, z) + f(x - 2*bx, y - 2*by, z)/3.; } -void BoundaryDirichlet_O3::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryDirichlet_O3::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { f(x, y, z) = (8./3)*val - 2.*f(x - bx, y - by, z) + f(x - 2*bx, y - 2*by, z)/3.; } -void BoundaryDirichlet_O3::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { +inline void BoundaryDirichlet_O3::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { f(x, y, z) = val; } -void BoundaryDirichlet_O3::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { +inline void BoundaryDirichlet_O3::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { f(x, y, z) = val; } -void BoundaryDirichlet_O3::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryDirichlet_O3::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { extrapolate3rd(f, x, bx, y, by, z); } -void BoundaryDirichlet_O3::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryDirichlet_O3::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { extrapolate3rd(f, x, bx, y, by, z); } @@ -753,24 +1082,24 @@ BoundaryOp* BoundaryDirichlet_O4::clone(BoundaryRegion *region, const list(region, args, keywords); } -void BoundaryDirichlet_O4::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryDirichlet_O4::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { f(x, y, z) = (16./5)*val - 3.*f(x - bx, y - by, z) + f(x - 2*bx, y - 2*by, z) - (1./5)*f(x - 3*bx, y - 3*by, z); } -void BoundaryDirichlet_O4::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryDirichlet_O4::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { f(x, y, z) = (16./5)*val - 3.*f(x - bx, y - by, z) + f(x - 2*bx, y - 2*by, z) - (1./5)*f(x - 3*bx, y - 3*by, z); } -void BoundaryDirichlet_O4::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { +inline void BoundaryDirichlet_O4::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { f(x, y, z) = val; } -void BoundaryDirichlet_O4::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { +inline void BoundaryDirichlet_O4::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { f(x, y, z) = val; } -void BoundaryDirichlet_O4::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryDirichlet_O4::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { extrapolate4th(f, x, bx, y, by, z); } -void BoundaryDirichlet_O4::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryDirichlet_O4::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { extrapolate4th(f, x, bx, y, by, z); } @@ -781,10 +1110,10 @@ BoundaryOp* BoundaryDirichlet_smooth::clone(BoundaryRegion *region, const list(region, args, keywords); } -void BoundaryDirichlet_smooth::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryDirichlet_smooth::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { f(x, y, z) = 5./3.*val - 0.5*f(x - bx, y - by, z) - 1./6.*f(x - 2*bx, y - 2*by, z); } -void BoundaryDirichlet_smooth::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryDirichlet_smooth::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { // Dirichlet bc using val and first grid point would be // fb = 2*val - f0 // using val and second grid point would be @@ -794,17 +1123,17 @@ void BoundaryDirichlet_smooth::applyAtPoint(Field3D &f, BoutReal val, int x, int f(x, y, z) = 5./3.*val - 0.5*f(x - bx, y - by, z) - 1./6.*f(x - 2*bx, y - 2*by, z); } -void BoundaryDirichlet_smooth::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { +inline void BoundaryDirichlet_smooth::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { f(x, y, z) = val; } -void BoundaryDirichlet_smooth::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { +inline void BoundaryDirichlet_smooth::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { f(x, y, z) = val; } -void BoundaryDirichlet_smooth::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryDirichlet_smooth::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { extrapolate2nd(f, x, bx, y, by, z); } -void BoundaryDirichlet_smooth::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryDirichlet_smooth::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { extrapolate2nd(f, x, bx, y, by, z); } @@ -819,24 +1148,24 @@ BoundaryOp* BoundaryDirichlet_2ndOrder::clone(BoundaryRegion *region, const list // 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 -void BoundaryDirichlet_2ndOrder::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryDirichlet_2ndOrder::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { f(x, y, z) = 8./3.*val - 2.*f(x - bx, y - by, z) + 1./3.*f(x - 2*bx, y - 2*by, z); } -void BoundaryDirichlet_2ndOrder::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryDirichlet_2ndOrder::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { f(x, y, z) = 8./3.*val - 2.*f(x - bx, y - by, z) + 1./3.*f(x - 2*bx, y - 2*by, z); } -void BoundaryDirichlet_2ndOrder::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { +inline void BoundaryDirichlet_2ndOrder::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { f(x, y, z) = val; } -void BoundaryDirichlet_2ndOrder::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { +inline void BoundaryDirichlet_2ndOrder::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { f(x, y, z) = val; } -void BoundaryDirichlet_2ndOrder::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryDirichlet_2ndOrder::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { extrapolate2nd(f, x, bx, y, by, z); } -void BoundaryDirichlet_2ndOrder::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryDirichlet_2ndOrder::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { extrapolate2nd(f, x, bx, y, by, z); } @@ -847,26 +1176,26 @@ BoundaryOp* BoundaryDirichlet_O5::clone(BoundaryRegion *region, const list(region, args, keywords); } -void BoundaryDirichlet_O5::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryDirichlet_O5::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { f(x, y, z) = 128./35.*val - 4.*f(x - bx, y - by, z) + 2.*f(x - 2*bx, y - 2*by, z) - 4./5.*f(x - 3*bx, y - 3*by, z) + 1./7.*f(x - 4*bx, y - 4*by, z); } -void BoundaryDirichlet_O5::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryDirichlet_O5::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { f(x, y, z) = 128./35.*val - 4.*f(x - bx, y - by, z) + 2.*f(x - 2*bx, y - 2*by, z) - 4./5.*f(x - 3*bx, y - 3*by, z) + 1./7.*f(x - 4*bx, y - 4*by, z); } -void BoundaryDirichlet_O5::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { +inline void BoundaryDirichlet_O5::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { f(x, y, z) = val; } -void BoundaryDirichlet_O5::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { +inline void BoundaryDirichlet_O5::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { f(x, y, z) = val; } -void BoundaryDirichlet_O5::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryDirichlet_O5::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { // Changing this extrapolation to not depend on val, so just using grid point // values. JTO 16/10/2018 extrapolate5th(f, x, bx, y, by, z); } -void BoundaryDirichlet_O5::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryDirichlet_O5::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { // Changing this extrapolation to not depend on val, so just using grid point // values. Not sure if this is the correct order... JTO 16/10/2018 extrapolate5th(f, x, bx, y, by, z); @@ -881,8 +1210,8 @@ BoundaryOp* BoundaryNeumann_NonOrthogonal::clone(BoundaryRegion *region, const l if (!args.empty()) { output << "WARNING: argument is set to BoundaryNeumann_NonOrthogonal\n"; // First argument should be a value - val = stringToReal(args.front()); - return new BoundaryNeumann_NonOrthogonal(region, val); + BoutReal val_in = stringToReal(args.front()); + return new BoundaryNeumann_NonOrthogonal(region, val_in); } if (!keywords.empty()) { // Given keywords, but not using @@ -946,10 +1275,10 @@ BoundaryOp* BoundaryNeumann2::clone(BoundaryRegion *region, const list & return boundaryCloneNoArguments(region, args, keywords); } -void BoundaryNeumann2::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryNeumann2::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { f(x, y, z) = (4.*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z))/3.; } -void BoundaryNeumann2::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryNeumann2::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { f(x, y, z) = (4.*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z))/3.; } @@ -960,10 +1289,10 @@ void BoundaryNeumann2::applyAtPointStaggered(Field3D &UNUSED(f), BoutReal UNUSED throw BoutException("BoundaryNeumann2 not implemented for staggered grids"); } -void BoundaryNeumann2::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryNeumann2::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { extrapolate2nd(f, x, bx, y, by, z); } -void BoundaryNeumann2::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryNeumann2::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { extrapolate2nd(f, x, bx, y, by, z); } @@ -976,24 +1305,24 @@ BoundaryOp* BoundaryNeumann_2ndOrder::clone(BoundaryRegion *region, const list(region, args, keywords); } -void BoundaryNeumann_2ndOrder::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { +inline void BoundaryNeumann_2ndOrder::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { f(x, y, z) = f(x - bx, y - by, z) + val*delta; } -void BoundaryNeumann_2ndOrder::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { +inline void BoundaryNeumann_2ndOrder::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { f(x, y, z) = f(x - bx, y - by, z) + val*delta; } -void BoundaryNeumann_2ndOrder::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { +inline void BoundaryNeumann_2ndOrder::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { f(x, y, z) = (4.*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z) + 2.*delta*val)/3.; } -void BoundaryNeumann_2ndOrder::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { +inline void BoundaryNeumann_2ndOrder::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { f(x, y, z) = (4.*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z) + 2.*delta*val)/3.; } -void BoundaryNeumann_2ndOrder::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryNeumann_2ndOrder::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { extrapolate2nd(f, x, bx, y, by, z); } -void BoundaryNeumann_2ndOrder::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryNeumann_2ndOrder::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { extrapolate2nd(f, x, bx, y, by, z); } @@ -1005,26 +1334,26 @@ BoundaryOp* BoundaryNeumann::clone(BoundaryRegion *region, const list &a return boundaryClone(region, args, keywords); } -void BoundaryNeumann::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { +inline void BoundaryNeumann::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { f(x, y, z) = f(x - bx, y - by, z) + delta*val; } -void BoundaryNeumann::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { +inline void BoundaryNeumann::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { f(x, y, z) = f(x - bx, y - by, z) + delta*val; } // For staggered case need to apply slightly differently Use one-sided // differencing. Cell is now on the boundary, so use one-sided differencing -void BoundaryNeumann::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { +inline void BoundaryNeumann::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { f(x, y, z) = (4.*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z) + 2.*delta*val)/3.; } -void BoundaryNeumann::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { +inline void BoundaryNeumann::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { f(x, y, z) = (4.*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z) + 2.*delta*val)/3.; } -void BoundaryNeumann::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryNeumann::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { extrapolate2nd(f, x, bx, y, by, z); } -void BoundaryNeumann::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryNeumann::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { extrapolate2nd(f, x, bx, y, by, z); } @@ -1037,32 +1366,32 @@ BoundaryOp* BoundaryNeumann_O4::clone(BoundaryRegion *region, const list return boundaryClone(region, args, keywords); } -void BoundaryNeumann_O4::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { +inline void BoundaryNeumann_O4::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { f(x, y, z) = 12.*delta*val/11. + ( 17.*f(x - bx, y - by, z) + 9.*f(x - 2*bx, y - 2*by, z) - 5.*f(x - 3*bx, y - 3*by, z) + f(x - 4*bx, y - 4*by, z))/22.; } -void BoundaryNeumann_O4::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { +inline void BoundaryNeumann_O4::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { f(x, y, z) = 12.*delta*val/11. + ( 17.*f(x - bx, y - by, z) + 9.*f(x - 2*bx, y - 2*by, z) - 5.*f(x - 3*bx, y - 3*by, z) + f(x - 4*bx, y - 4*by, z))/22.; } -void BoundaryNeumann_O4::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { +inline void BoundaryNeumann_O4::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { f(x, y, z) = 12./25.*(delta*val + 4.*f(x - bx, y - by, z) - 3.*f(x - 2*bx, y - 2*by, z) + 4./3.*f(x - 3*bx, y - 3*by, z) - 1./4.*f(x - 4*bx, y - 4*by, z)); } -void BoundaryNeumann_O4::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { +inline void BoundaryNeumann_O4::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { f(x, y, z) = 12./25.*(delta*val + 4.*f(x - bx, y - by, z) - 3.*f(x - 2*bx, y - 2*by, z) + 4./3.*f(x - 3*bx, y - 3*by, z) - 1./4.*f(x - 4*bx, y - 4*by, z)); } -void BoundaryNeumann_O4::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryNeumann_O4::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { extrapolate5th(f, x, bx, y, by, z); } -void BoundaryNeumann_O4::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryNeumann_O4::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { extrapolate5th(f, x, bx, y, by, z); } @@ -1073,10 +1402,10 @@ BoundaryOp* BoundaryNeumann_4thOrder::clone(BoundaryRegion *region, const list(region, args, keywords); } -void BoundaryNeumann_4thOrder::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { +inline void BoundaryNeumann_4thOrder::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { f(x, y, z) = 12.*delta/11.*val + 17./22.*f(x - bx, y - by, z) + 9./22.*f(x - 2*bx, y - 2*by, z) - 5./22.*f(x - 3*bx, y - 3*by, z) + 1./22.*f(x - 4*bx, y - 4*by, z); } -void BoundaryNeumann_4thOrder::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { +inline void BoundaryNeumann_4thOrder::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { f(x, y, z) = 12.*delta/11.*val + 17./22.*f(x - bx, y - by, z) + 9./22.*f(x - 2*bx, y - 2*by, z) - 5./22.*f(x - 3*bx, y - 3*by, z) + 1./22.*f(x - 4*bx, y - 4*by, z); } @@ -1087,14 +1416,14 @@ void BoundaryNeumann_4thOrder::applyAtPointStaggered(Field3D &UNUSED(f), BoutRea throw BoutException("BoundaryNeumann_4thOrder is not implemented for staggered grids."); } -void BoundaryNeumann_4thOrder::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryNeumann_4thOrder::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { // Changing this extrapolation to not depend on val, so just using grid point // values. Previously was: // f(x+bx,y+by,z) = -24.*delta*val + 27.*f(x,y,z) - 27.*f(x-bx,y-by,z) + f(x-2*bx,y-2*by,z); // The f(x-4*bx,y-4*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 // - JTO 16/10/2018 extrapolate5th(f, x, bx, y, by, z); } -void BoundaryNeumann_4thOrder::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryNeumann_4thOrder::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { // Changing this extrapolation to not depend on val, so just using grid point // values. Previously was // f(x+bx,y+by,z) = -24.*delta*val + 27.*f(x,y,z) - 27.*f(x-bx,y-by,z) + f(x-2*bx,y-2*by,z); // The f(x-4*bx,y-4*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 @@ -1180,10 +1509,10 @@ BoundaryOp* BoundaryConstGradient::clone(BoundaryRegion *region, const list(region, args, keywords); } -void BoundaryConstGradient::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryConstGradient::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { f(x, y, z) = 2.*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z); } -void BoundaryConstGradient::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryConstGradient::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { f(x, y, z) = 2.*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z); } @@ -1194,10 +1523,10 @@ void BoundaryConstGradient::applyAtPointStaggered(Field3D &UNUSED(f), BoutReal U throw BoutException("BoundaryConstGradient is not implemented for staggered grids."); } -void BoundaryConstGradient::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryConstGradient::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { extrapolate2nd(f, x, bx, y, by, z); } -void BoundaryConstGradient::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryConstGradient::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { extrapolate2nd(f, x, bx, y, by, z); } @@ -1582,24 +1911,24 @@ BoundaryOp* BoundaryFree_O2::clone(BoundaryRegion *region, const list &a return boundaryCloneNoArguments(region, args, keywords); } -void BoundaryFree_O2::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryFree_O2::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate2nd(f, x, bx, y, by, z); } -void BoundaryFree_O2::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryFree_O2::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate2nd(f, x, bx, y, by, z); } -void BoundaryFree_O2::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryFree_O2::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate2nd(f, x, bx, y, by, z); } -void BoundaryFree_O2::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryFree_O2::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate2nd(f, x, bx, y, by, z); } -void BoundaryFree_O2::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryFree_O2::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { extrapolate2nd(f, x, bx, y, by, z); } -void BoundaryFree_O2::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryFree_O2::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { extrapolate2nd(f, x, bx, y, by, z); } @@ -1611,24 +1940,24 @@ BoundaryOp* BoundaryFree_O3::clone(BoundaryRegion *region, const list &a return boundaryCloneNoArguments(region, args, keywords); } -void BoundaryFree_O3::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryFree_O3::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate3rd(f, x, bx, y, by, z); } -void BoundaryFree_O3::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryFree_O3::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate3rd(f, x, bx, y, by, z); } -void BoundaryFree_O3::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryFree_O3::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate3rd(f, x, bx, y, by, z); } -void BoundaryFree_O3::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryFree_O3::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate3rd(f, x, bx, y, by, z); } -void BoundaryFree_O3::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryFree_O3::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { extrapolate3rd(f, x, bx, y, by, z); } -void BoundaryFree_O3::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryFree_O3::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { extrapolate3rd(f, x, bx, y, by, z); } @@ -1638,24 +1967,24 @@ BoundaryOp* BoundaryFree_O4::clone(BoundaryRegion *region, const list &a return boundaryCloneNoArguments(region, args, keywords); } -void BoundaryFree_O4::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryFree_O4::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate4th(f, x, bx, y, by, z); } -void BoundaryFree_O4::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryFree_O4::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate4th(f, x, bx, y, by, z); } -void BoundaryFree_O4::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryFree_O4::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate4th(f, x, bx, y, by, z); } -void BoundaryFree_O4::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryFree_O4::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate4th(f, x, bx, y, by, z); } -void BoundaryFree_O4::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryFree_O4::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { extrapolate4th(f, x, bx, y, by, z); } -void BoundaryFree_O4::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryFree_O4::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { extrapolate4th(f, x, bx, y, by, z); } @@ -1665,24 +1994,24 @@ BoundaryOp* BoundaryFree_O5::clone(BoundaryRegion *region, const list &a return boundaryCloneNoArguments(region, args, keywords); } -void BoundaryFree_O5::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryFree_O5::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate5th(f, x, bx, y, by, z); } -void BoundaryFree_O5::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryFree_O5::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate5th(f, x, bx, y, by, z); } -void BoundaryFree_O5::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryFree_O5::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate5th(f, x, bx, y, by, z); } -void BoundaryFree_O5::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryFree_O5::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate5th(f, x, bx, y, by, z); } -void BoundaryFree_O5::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryFree_O5::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { extrapolate5th(f, x, bx, y, by, z); } -void BoundaryFree_O5::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryFree_O5::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { extrapolate5th(f, x, bx, y, by, z); } From 9e1618160873dedca046ad94d2fc104bb3eb4c1d Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 7 Nov 2018 13:40:37 +0000 Subject: [PATCH 38/45] clang-format, remove commented-out code --- include/boundary_op.hxx | 82 +- include/boundary_standard.hxx | 552 +++++---- src/mesh/boundary_op.cxx | 8 +- src/mesh/boundary_standard.cxx | 2073 +++++++++++++++++++------------- 4 files changed, 1572 insertions(+), 1143 deletions(-) diff --git a/include/boundary_op.hxx b/include/boundary_op.hxx index b0b851bdd4..c365270f34 100644 --- a/include/boundary_op.hxx +++ b/include/boundary_op.hxx @@ -8,38 +8,39 @@ class BoundaryModifier; #include "boundary_region.hxx" #include "field2d.hxx" #include "field3d.hxx" +#include "unused.hxx" #include "vector2d.hxx" #include "vector3d.hxx" -#include "unused.hxx" #include -#include #include #include +#include using std::string; using std::list; /// An operation on a boundary class BoundaryOp { public: - BoundaryOp(bool apply_ddt = false) : bndry(nullptr), apply_to_ddt(apply_ddt), - val(0.), gen(nullptr), width(0) {} + BoundaryOp(bool apply_ddt = false) + : bndry(nullptr), apply_to_ddt(apply_ddt), val(0.), gen(nullptr), width(0) {} BoundaryOp(BoundaryRegion *region, int width_in = 0, bool apply_ddt = false) - : bndry(region), apply_to_ddt(apply_ddt), val(0.), gen(nullptr), - width(width_in ? width_in : region->width) {} - BoundaryOp(BoundaryRegion *region, BoutReal val_in, std::shared_ptr g, int width_in = 0) - : bndry(region), apply_to_ddt(false), val(val_in), gen(std::move(g)), - width(width_in ? width_in : region->width) {} + : bndry(region), apply_to_ddt(apply_ddt), val(0.), gen(nullptr), + width(width_in ? width_in : region->width) {} + BoundaryOp(BoundaryRegion *region, BoutReal val_in, std::shared_ptr g, + int width_in = 0) + : bndry(region), apply_to_ddt(false), val(val_in), gen(std::move(g)), + width(width_in ? width_in : region->width) {} virtual ~BoundaryOp() {} // Note: All methods must implement clone, except for modifiers (see below) - virtual BoundaryOp *clone(BoundaryRegion *UNUSED(region), const list &UNUSED(args), + virtual BoundaryOp *clone(BoundaryRegion *UNUSED(region), + const list &UNUSED(args), const std::map &UNUSED(keywords)) { throw BoutException("BoundaryOp::clone not implemented"); return nullptr; } - /// Apply a boundary condition on field f virtual void apply(Field2D &f, BoutReal t = 0.) = 0; virtual void apply(Field3D &f, BoutReal t = 0.) = 0; @@ -59,76 +60,51 @@ public: /// Apply a boundary condition on ddt(f) virtual void apply_ddt(Field2D &f); virtual void apply_ddt(Field3D &f); - virtual void apply_ddt(Vector2D &f) { - apply(ddt(f)); - } - virtual void apply_ddt(Vector3D &f) { - apply(ddt(f)); - } + virtual void apply_ddt(Vector2D &f) { apply(ddt(f)); } + virtual void apply_ddt(Vector3D &f) { apply(ddt(f)); } BoundaryRegion *bndry; - const bool apply_to_ddt; // True if this boundary condition should be applied on the time derivatives, false if it should be applied to the field values + const bool apply_to_ddt; // True if this boundary condition should be applied on the + // time derivatives, false if it should be applied to the field + // values protected: - const BoutReal val; // constant value for boundary condition + const BoutReal val; // constant value for boundary condition std::shared_ptr gen; // Generator const int width; // boundary width, stored in case we change it from the default }; /// An operation on a boundary -template +template class BoundaryOpWithApply : public BoundaryOp { public: using BoundaryOp::BoundaryOp; // Note: All methods must implement clone, except for modifiers (see below) - virtual BoundaryOp* clone(BoundaryRegion *UNUSED(region), const list &UNUSED(args)) { + virtual BoundaryOp *clone(BoundaryRegion *UNUSED(region), + const list &UNUSED(args)) { ASSERT1(false); // this implementation should never get called return nullptr; } /// Apply a boundary condition on field f - void apply(Field2D &f, BoutReal t = 0.) override { - applyTemplate(f, t); - } - void apply(Field3D &f, BoutReal t = 0.) override { - applyTemplate(f, t); - } - -protected: - //// Apply boundary condition at a point - //virtual void applyAtPoint(Field2D &UNUSED(f), BoutReal UNUSED(val), int - // UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), - // Coordinates* UNUSED(metric)) = 0; - //virtual void applyAtPoint(Field3D &UNUSED(f), BoutReal UNUSED(val), int - // UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), - // Coordinates* UNUSED(metric)) = 0; - - //// Apply to staggered grid - //virtual void applyAtPointStaggered(Field2D &UNUSED(f), BoutReal UNUSED(val), - // int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int - // UNUSED(z), Coordinates* UNUSED(metric)) = 0; - //virtual void applyAtPointStaggered(Field3D &UNUSED(f), BoutReal UNUSED(val), - // int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int - // UNUSED(z), Coordinates* UNUSED(metric)) = 0; - - //// extrapolate to further guard cells - //virtual void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) = 0; - //virtual void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) = 0; + void apply(Field2D &f, BoutReal t = 0.) override { applyTemplate(f, t); } + void apply(Field3D &f, BoutReal t = 0.) override { applyTemplate(f, t); } private: - template - void applyTemplate(T &f, BoutReal t); + template void applyTemplate(T &f, BoutReal t); }; class BoundaryModifier : public BoundaryOp { public: BoundaryModifier(bool apply_ddt = false) : BoundaryOp(apply_ddt), op(nullptr) {} BoundaryModifier(BoundaryOp *operation, bool apply_ddt = false) - : BoundaryOp(operation->bndry, 0, apply_ddt), op(operation) {} - virtual BoundaryOp* cloneMod(BoundaryOp *op, const list &args) = 0; - virtual BoundaryOpPar* cloneMod(BoundaryOpPar *UNUSED(op), const list &UNUSED(args)) { + : BoundaryOp(operation->bndry, 0, apply_ddt), op(operation) {} + virtual BoundaryOp *cloneMod(BoundaryOp *op, const list &args) = 0; + virtual BoundaryOpPar *cloneMod(BoundaryOpPar *UNUSED(op), + const list &UNUSED(args)) { throw BoutException("BoundaryModifier should not be called on a BoundaryOpPar."); } + protected: BoundaryOp *op; }; diff --git a/include/boundary_standard.hxx b/include/boundary_standard.hxx index bbeb8ed708..9e3d76abea 100644 --- a/include/boundary_standard.hxx +++ b/include/boundary_standard.hxx @@ -5,198 +5,251 @@ #include "boundary_op.hxx" #include "bout_types.hxx" -#include #include "unused.hxx" +#include #include /// Dirichlet (set to zero) boundary condition class BoundaryDirichlet : public BoundaryOp { - public: +public: using BoundaryOp::BoundaryOp; // inherit BoundaryOp constructors - BoundaryOp* clone(BoundaryRegion *region, const list &args, - const std::map &keywords) override; + BoundaryOp *clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; - void apply(Field2D &f,BoutReal t = 0.) final { - applyTemplate(f, t); - } - void apply(Field3D &f,BoutReal t = 0.) final { - applyTemplate(f, t); - } + void apply(Field2D &f, BoutReal t = 0.) final { applyTemplate(f, t); } + void apply(Field3D &f, BoutReal t = 0.) final { applyTemplate(f, t); } - private: - template - void applyTemplate(T &f, BoutReal t); +private: + template void applyTemplate(T &f, BoutReal t); }; BoutReal default_func(BoutReal t, int x, int y, int z); /// 3nd-order boundary condition class BoundaryDirichlet_O3 : public BoundaryOpWithApply { - public: - using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOp constructors - BoundaryOp* clone(BoundaryRegion *region, const list &args, - const std::map &keywords) override; - - static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); +public: + using BoundaryOpWithApply< + BoundaryDirichlet_O3>::BoundaryOpWithApply; // inherit BoundaryOp constructors + BoundaryOp *clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; + + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, + BoutReal delta); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, + BoutReal delta); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, + int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, + int by, int z, BoutReal delta); static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; /// 4th-order boundary condition class BoundaryDirichlet_O4 : public BoundaryOpWithApply { - public: - using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors - BoundaryOp* clone(BoundaryRegion *region, const list &args, - const std::map &keywords) override; - - static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); +public: + using BoundaryOpWithApply:: + BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors + BoundaryOp *clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; + + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, + BoutReal delta); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, + BoutReal delta); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, + int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, + int by, int z, BoutReal delta); static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; -/// Dirichlet boundary condition, tries to smooth out grid-scale oscillations at the boundary +/// Dirichlet boundary condition, tries to smooth out grid-scale oscillations at the +/// boundary class BoundaryDirichlet_smooth : public BoundaryOpWithApply { - public: - using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors - BoundaryOp* clone(BoundaryRegion *region, const list &args, - const std::map &keywords) override; - - static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); +public: + using BoundaryOpWithApply:: + BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors + BoundaryOp *clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; + + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, + BoutReal delta); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, + BoutReal delta); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, + int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, + int by, int z, BoutReal delta); static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; -/// Dirichlet boundary condition set half way between guard cell and grid cell at 2nd order accuracy -class BoundaryDirichlet_2ndOrder : public BoundaryOpWithApply { - public: - using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors - BoundaryOp* clone(BoundaryRegion *region, const list &args, - const std::map &keywords) override; - - static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); +/// Dirichlet boundary condition set half way between guard cell and grid cell at 2nd +/// order accuracy +class BoundaryDirichlet_2ndOrder + : public BoundaryOpWithApply { +public: + using BoundaryOpWithApply:: + BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors + BoundaryOp *clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; + + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, + BoutReal delta); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, + BoutReal delta); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, + int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, + int by, int z, BoutReal delta); static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; -/// Dirichlet boundary condition set half way between guard cell and grid cell at 4th order accuracy +/// Dirichlet boundary condition set half way between guard cell and grid cell at 4th +/// order accuracy class BoundaryDirichlet_O5 : public BoundaryOpWithApply { - public: - using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors - BoundaryOp* clone(BoundaryRegion *region, const list &args, - const std::map &keywords) override; - - static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); +public: + using BoundaryOpWithApply:: + BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors + BoundaryOp *clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; + + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, + BoutReal delta); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, + BoutReal delta); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, + int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, + int by, int z, BoutReal delta); static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; /// Neumann (zero-gradient) boundary condition for non-orthogonal meshes class BoundaryNeumann_NonOrthogonal : public BoundaryOp { - public: +public: BoundaryNeumann_NonOrthogonal() {} - BoundaryNeumann_NonOrthogonal(BoutReal setval): BoundaryOp(nullptr, setval, nullptr, 0) {} - BoundaryNeumann_NonOrthogonal(BoundaryRegion *region, BoutReal setval=0.):BoundaryOp(region, setval, nullptr, 0) {} - BoundaryOp* clone(BoundaryRegion *region, const list &args, - const std::map &keywords) override; + BoundaryNeumann_NonOrthogonal(BoutReal setval) + : BoundaryOp(nullptr, setval, nullptr, 0) {} + BoundaryNeumann_NonOrthogonal(BoundaryRegion *region, BoutReal setval = 0.) + : BoundaryOp(region, setval, nullptr, 0) {} + BoundaryOp *clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; - void apply(Field2D &f, BoutReal t = 0.) final { - applyTemplate(f, t); - } - void apply(Field3D &f, BoutReal t = 0.) final { - applyTemplate(f, t); - } - private: - template - void applyTemplate(T &f, BoutReal t); + void apply(Field2D &f, BoutReal t = 0.) final { applyTemplate(f, t); } + void apply(Field3D &f, BoutReal t = 0.) final { applyTemplate(f, t); } + +private: + template void applyTemplate(T &f, BoutReal t); }; /// Neumann (zero-gradient) boundary condition, using 2nd order on boundary class BoundaryNeumann2 : public BoundaryOpWithApply { - public: - using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors - BoundaryOp* clone(BoundaryRegion *region, const list &args, - const std::map &keywords) override; - - static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); +public: + using BoundaryOpWithApply< + BoundaryNeumann2>::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors + BoundaryOp *clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; + + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, + BoutReal delta); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, + BoutReal delta); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, + int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, + int by, int z, BoutReal delta); static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; -/// Neumann boundary condition set half way between guard cell and grid cell at 2nd order accuracy -class BoundaryNeumann_2ndOrder : public BoundaryOpWithApply { - public: - using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors - BoundaryOp* clone(BoundaryRegion *region, const list &args, - const std::map &keywords) override; - - static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); +/// Neumann boundary condition set half way between guard cell and grid cell at 2nd order +/// accuracy +class BoundaryNeumann_2ndOrder + : public BoundaryOpWithApply { +public: + using BoundaryOpWithApply:: + BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors + BoundaryOp *clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; + + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, + BoutReal delta); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, + BoutReal delta); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, + int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, + int by, int z, BoutReal delta); static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; -// Neumann boundary condition set half way between guard cell and grid cell at 2nd order accuracy +// Neumann boundary condition set half way between guard cell and grid cell at 2nd order +// accuracy class BoundaryNeumann : public BoundaryOpWithApply { - public: - using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors - BoundaryOp* clone(BoundaryRegion *region, const list &args, - const std::map &keywords) override; - - static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); +public: + using BoundaryOpWithApply:: + BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors + BoundaryOp *clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; + + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, + BoutReal delta); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, + BoutReal delta); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, + int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, + int by, int z, BoutReal delta); static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; -/// Neumann boundary condition set half way between guard cell and grid cell at 4th order accuracy +/// Neumann boundary condition set half way between guard cell and grid cell at 4th order +/// accuracy class BoundaryNeumann_O4 : public BoundaryOpWithApply { - public: - using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors - BoundaryOp* clone(BoundaryRegion *region, const list &args, - const std::map &keywords) override; - - static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); +public: + using BoundaryOpWithApply:: + BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors + BoundaryOp *clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; + + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, + BoutReal delta); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, + BoutReal delta); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, + int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, + int by, int z, BoutReal delta); static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; -/// Neumann boundary condition set half way between guard cell and grid cell at 4th order accuracy -class BoundaryNeumann_4thOrder : public BoundaryOpWithApply { - public: - using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors - BoundaryOp* clone(BoundaryRegion *region, const list &args, - const std::map &keywords) override; - - static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); +/// Neumann boundary condition set half way between guard cell and grid cell at 4th order +/// accuracy +class BoundaryNeumann_4thOrder + : public BoundaryOpWithApply { +public: + using BoundaryOpWithApply:: + BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors + BoundaryOp *clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; + + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, + BoutReal delta); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, + BoutReal delta); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, + int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, + int by, int z, BoutReal delta); static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; @@ -204,65 +257,62 @@ class BoundaryNeumann_4thOrder : public BoundaryOpWithApply &args, - const std::map &keywords) override; + BoundaryOp *clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; - void apply(Field2D &f, BoutReal t = 0.) final { - applyTemplate(f, t); - } - void apply(Field3D &f, BoutReal t = 0.) final { - applyTemplate(f, t); - } - private: - template - void applyTemplate(T &f, BoutReal t); + void apply(Field2D &f, BoutReal t = 0.) final { applyTemplate(f, t); } + void apply(Field3D &f, BoutReal t = 0.) final { applyTemplate(f, t); } + +private: + template void applyTemplate(T &f, BoutReal t); }; /// Robin (mix of Dirichlet and Neumann) class BoundaryRobin : public BoundaryOp { - public: +public: BoundaryRobin() : aval(0.), bval(0.), gval(0.) {} BoundaryRobin(BoundaryRegion *region, BoutReal a, BoutReal b, BoutReal g) - : BoundaryOp(region), aval(a), bval(b), gval(g) { } - BoundaryOp* clone(BoundaryRegion *region, const list &args, - const std::map &keywords) override; + : BoundaryOp(region), aval(a), bval(b), gval(g) {} + BoundaryOp *clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; - void apply(Field2D &f, BoutReal t = 0.) final { - applyTemplate(f, t); - } - void apply(Field3D &f, BoutReal t = 0.) final { - applyTemplate(f, t); - } - private: + void apply(Field2D &f, BoutReal t = 0.) final { applyTemplate(f, t); } + void apply(Field3D &f, BoutReal t = 0.) final { applyTemplate(f, t); } + +private: const BoutReal aval, bval, gval; - template - void applyTemplate(T &f, BoutReal t); + template void applyTemplate(T &f, BoutReal t); }; /// Constant gradient (zero second derivative) class BoundaryConstGradient : public BoundaryOpWithApply { - public: - using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors - BoundaryOp* clone(BoundaryRegion *region, const list &args, - const std::map &keywords) override; - - static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); +public: + using BoundaryOpWithApply:: + BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors + BoundaryOp *clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; + + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, + BoutReal delta); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, + BoutReal delta); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, + int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, + int by, int z, BoutReal delta); static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; /// Zero Laplacian, decaying solution class BoundaryZeroLaplace : public BoundaryOp { - public: +public: using BoundaryOp::BoundaryOp; - BoundaryOp* clone(BoundaryRegion *region, const list &args, - const std::map &keywords) override; + BoundaryOp *clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; void apply(Field2D &f, BoutReal t) final; void apply(Field3D &f, BoutReal t) final; @@ -270,10 +320,10 @@ class BoundaryZeroLaplace : public BoundaryOp { /// Zero Laplacian class BoundaryZeroLaplace2 : public BoundaryOp { - public: +public: using BoundaryOp::BoundaryOp; - BoundaryOp* clone(BoundaryRegion *region, const list &args, - const std::map &keywords) override; + BoundaryOp *clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; void apply(Field2D &f, BoutReal t) final; void apply(Field3D &f, BoutReal t) final; @@ -281,10 +331,10 @@ class BoundaryZeroLaplace2 : public BoundaryOp { /// Constant Laplacian, decaying solution class BoundaryConstLaplace : public BoundaryOp { - public: +public: using BoundaryOp::BoundaryOp; - BoundaryOp* clone(BoundaryRegion *region, const list &args, - const std::map &keywords) override; + BoundaryOp *clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; void apply(Field2D &f, BoutReal t) final; void apply(Field3D &f, BoutReal t) final; @@ -292,23 +342,28 @@ class BoundaryConstLaplace : public BoundaryOp { /// Vector boundary condition Div(B) = 0, Curl(B) = 0 class BoundaryDivCurl : public BoundaryOp { - public: +public: using BoundaryOp::BoundaryOp; - BoundaryOp* clone(BoundaryRegion *region, const list &args, - const std::map &keywords) override; + BoundaryOp *clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; - void apply(Field2D &UNUSED(f), BoutReal UNUSED(t)) final { throw BoutException("ERROR: DivCurl boundary only for vectors"); } - void apply(Field3D &UNUSED(f), BoutReal UNUSED(t)) final { throw BoutException("ERROR: DivCurl boundary only for vectors"); } + void apply(Field2D &UNUSED(f), BoutReal UNUSED(t)) final { + throw BoutException("ERROR: DivCurl boundary only for vectors"); + } + void apply(Field3D &UNUSED(f), BoutReal UNUSED(t)) final { + throw BoutException("ERROR: DivCurl boundary only for vectors"); + } void apply(Vector2D &f) final; void apply(Vector3D &f) final; }; -/// Free boundary condition (evolve the field in the guard cells, using non-centred derivatives to calculate the ddt) +/// Free boundary condition (evolve the field in the guard cells, using non-centred +/// derivatives to calculate the ddt) class BoundaryFree : public BoundaryOp { - public: +public: using BoundaryOp::BoundaryOp; // inherit BoundaryOpWithApply constructors - BoundaryOp* clone(BoundaryRegion *region, const list &args, - const std::map &keywords) override; + BoundaryOp *clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; void apply(Field2D &f, BoutReal t) final; void apply(Field3D &f, BoutReal t) final; @@ -318,31 +373,42 @@ class BoundaryFree : public BoundaryOp { }; // L. Easy -/// Alternative free boundary condition (evolve the field in the guard cells, using non-centred derivatives to calculate the ddt) +/// Alternative free boundary condition (evolve the field in the guard cells, using +/// non-centred derivatives to calculate the ddt) class BoundaryFree_O2 : public BoundaryOpWithApply { public: - using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors - BoundaryOp* clone(BoundaryRegion *region, const list &args, - const std::map &keywords) override; - - static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + using BoundaryOpWithApply< + BoundaryFree_O2>::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors + BoundaryOp *clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; + + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, + BoutReal delta); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, + BoutReal delta); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, + int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, + int by, int z, BoutReal delta); static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; class BoundaryFree_O3 : public BoundaryOpWithApply { public: - using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors - BoundaryOp* clone(BoundaryRegion *region, const list &args, - const std::map &keywords) override; - - static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + using BoundaryOpWithApply< + BoundaryFree_O3>::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors + BoundaryOp *clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; + + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, + BoutReal delta); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, + BoutReal delta); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, + int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, + int by, int z, BoutReal delta); static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; @@ -350,28 +416,38 @@ public: class BoundaryFree_O4 : public BoundaryOpWithApply { public: - using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors - BoundaryOp* clone(BoundaryRegion *region, const list &args, - const std::map &keywords) override; - - static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + using BoundaryOpWithApply< + BoundaryFree_O4>::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors + BoundaryOp *clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; + + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, + BoutReal delta); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, + BoutReal delta); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, + int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, + int by, int z, BoutReal delta); static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; class BoundaryFree_O5 : public BoundaryOpWithApply { public: - using BoundaryOpWithApply::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors - BoundaryOp* clone(BoundaryRegion *region, const list &args, - const std::map &keywords) override; - - static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); - static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta); + using BoundaryOpWithApply< + BoundaryFree_O5>::BoundaryOpWithApply; // inherit BoundaryOpWithApply constructors + BoundaryOp *clone(BoundaryRegion *region, const list &args, + const std::map &keywords) override; + + static void applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, + BoutReal delta); + static void applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, + BoutReal delta); + static void applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, + int by, int z, BoutReal delta); + static void applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, + int by, int z, BoutReal delta); static void extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z); static void extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z); }; @@ -380,17 +456,21 @@ public: /// Convert a boundary condition to a relaxing one class BoundaryRelax : public BoundaryModifier { - public: - BoundaryRelax() : BoundaryModifier(true), r(10.) {} // Set default rate - BoundaryRelax(BoundaryOp *operation, BoutReal rate) : BoundaryModifier(operation, true) { r = fabs(rate); } - BoundaryOp* cloneMod(BoundaryOp *op, const list &args) final; +public: + BoundaryRelax() : BoundaryModifier(true), r(10.) {} // Set default rate + BoundaryRelax(BoundaryOp *operation, BoutReal rate) + : BoundaryModifier(operation, true) { + r = fabs(rate); + } + BoundaryOp *cloneMod(BoundaryOp *op, const list &args) final; void apply(Field2D &f, BoutReal t) final; void apply(Field3D &f, BoutReal t) final; void apply_ddt(Field2D &f) final; void apply_ddt(Field3D &f) final; - private: + +private: BoutReal r; }; @@ -398,50 +478,58 @@ class BoundaryRelax : public BoundaryModifier { class BoundaryWidth : public BoundaryModifier { public: BoundaryWidth() : width(2) {} - BoundaryWidth(BoundaryOp *operation, int wid) : BoundaryModifier(operation), width(wid) {} - BoundaryOp* cloneMod(BoundaryOp *UNUSED(op), const list &UNUSED(args)) override { - throw BoutException("WARNING: BoundaryWidth modifier is deprecated, use 'width' keyword to boundary conditions instead"); + BoundaryWidth(BoundaryOp *operation, int wid) + : BoundaryModifier(operation), width(wid) {} + BoundaryOp *cloneMod(BoundaryOp *UNUSED(op), + const list &UNUSED(args)) override { + throw BoutException("WARNING: BoundaryWidth modifier is deprecated, use 'width' " + "keyword to boundary conditions instead"); return new BoundaryWidth(nullptr, 0); } - void apply(Field2D &UNUSED(f), BoutReal UNUSED(t)) override {}; - void apply(Field3D &UNUSED(f), BoutReal UNUSED(t)) override {}; + void apply(Field2D &UNUSED(f), BoutReal UNUSED(t)) override{}; + void apply(Field3D &UNUSED(f), BoutReal UNUSED(t)) override{}; + + void apply_ddt(Field2D &UNUSED(f)) override{}; + void apply_ddt(Field3D &UNUSED(f)) override{}; - void apply_ddt(Field2D &UNUSED(f)) override {}; - void apply_ddt(Field3D &UNUSED(f)) override {}; private: int width; }; -/// Convert input field fromFieldAligned, apply boundary and then convert back toFieldAligned +/// Convert input field fromFieldAligned, apply boundary and then convert back +/// toFieldAligned /// Equivalent to converting the boundary condition to "Field Aligned" from "orthogonal" class BoundaryToFieldAligned : public BoundaryModifier { public: - BoundaryToFieldAligned(){} - BoundaryToFieldAligned(BoundaryOp *operation) : BoundaryModifier(operation){} - BoundaryOp* cloneMod(BoundaryOp *op, const list &args) final; + BoundaryToFieldAligned() {} + BoundaryToFieldAligned(BoundaryOp *operation) : BoundaryModifier(operation) {} + BoundaryOp *cloneMod(BoundaryOp *op, const list &args) final; void apply(Field2D &f, BoutReal t) final; void apply(Field3D &f, BoutReal t) final; void apply_ddt(Field2D &f) final; void apply_ddt(Field3D &f) final; + private: }; -/// Convert input field toFieldAligned, apply boundary and then convert back fromFieldAligned +/// Convert input field toFieldAligned, apply boundary and then convert back +/// fromFieldAligned /// Equivalent to converting the boundary condition from "Field Aligned" to "orthogonal" class BoundaryFromFieldAligned : public BoundaryModifier { public: - BoundaryFromFieldAligned(){} - BoundaryFromFieldAligned(BoundaryOp *operation) : BoundaryModifier(operation){} - BoundaryOp* cloneMod(BoundaryOp *op, const list &args) final; + BoundaryFromFieldAligned() {} + BoundaryFromFieldAligned(BoundaryOp *operation) : BoundaryModifier(operation) {} + BoundaryOp *cloneMod(BoundaryOp *op, const list &args) final; void apply(Field2D &f, BoutReal t) final; void apply(Field3D &f, BoutReal t) final; void apply_ddt(Field2D &f) final; void apply_ddt(Field3D &f) final; + private: }; diff --git a/src/mesh/boundary_op.cxx b/src/mesh/boundary_op.cxx index d3cc7278a3..c4576b872b 100644 --- a/src/mesh/boundary_op.cxx +++ b/src/mesh/boundary_op.cxx @@ -26,14 +26,14 @@ void BoundaryOp::apply_ddt(Field2D &f) { Field2D *dt = f.timeDeriv(); - for(bndry->first(); !bndry->isDone(); bndry->next()) - for(int z=0; zfirst(); !bndry->isDone(); bndry->next()) + for (int z = 0; z < f.getNz(); z++) (*dt)(bndry->x, bndry->y, z) = 0.; // Set time derivative to zero } void BoundaryOp::apply_ddt(Field3D &f) { Field3D *dt = f.timeDeriv(); - for(bndry->first(); !bndry->isDone(); bndry->next()) - for(int z=0; zfirst(); !bndry->isDone(); bndry->next()) + for (int z = 0; z < f.getNz(); z++) (*dt)(bndry->x, bndry->y, z) = 0.; // Set time derivative to zero } diff --git a/src/mesh/boundary_standard.cxx b/src/mesh/boundary_standard.cxx index d0c6402082..03e22f3f0a 100644 --- a/src/mesh/boundary_standard.cxx +++ b/src/mesh/boundary_standard.cxx @@ -1,19 +1,19 @@ -#include #include -#include -#include -#include -#include -#include -#include #include +#include #include +#include +#include +#include +#include +#include +#include /////////////////////////////////////////////////////////////// // Helpers /** \brief Check that there are sufficient non-boundary points for desired B.C. - + Checks both the size of the global grid (i.e. if this B.C. could be ok for some parallel setup or not) and the local grid. @@ -22,157 +22,163 @@ more explanatory message. */ namespace { - void verifyNumPoints(BoundaryRegion *region, int ptsRequired) { - TRACE("Verifying number of points available for BC"); +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 - Mesh* localmesh = region->localmesh; - - 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"; - - //Here 2*localmesh->xstart is the total number of guard/boundary cells - ptsAvailGlobal = localmesh->GlobalNx - 2*localmesh->xstart; - - //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; - - //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; + Mesh *localmesh = region->localmesh; + + 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"; + + // Here 2*localmesh->xstart is the total number of guard/boundary cells + ptsAvailGlobal = localmesh->GlobalNx - 2 * localmesh->xstart; + + // 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; + + // 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"; } - case BNDRY_YUP: - case BNDRY_YDOWN: { - side = "y"; - - //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; - } - default : { - throw BoutException("Unrecognised boundary region (%s) for verifyNumPoints.",region->location); - } - } - - //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); + break; + } + case BNDRY_YUP: + case BNDRY_YDOWN: { + side = "y"; + + // 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"; } -#endif + break; } - - // 2nd order extrapolation to a point - template - void extrapolate2nd(T &f, int x, int bx, int y, int by, int z) { - f(x, y, z) = 2*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z); + default: { + throw BoutException("Unrecognised boundary region (%s) for verifyNumPoints.", + region->location); } - - // 3rd order extrapolation to a point - template - void extrapolate3rd(T &f, int x, int bx, int y, int by, int z) { - f(x, y, z) = 3.0*f(x - bx, y - by, z) - 3.0*f(x - 2*bx, y - 2*by, z) + f(x - 3*bx, y - 3*by, z); } - // 4th order extrapolation to a point - template - void extrapolate4th(T &f, int x, int bx, int y, int by, int z) { - f(x, y, z) = 4.0*f(x - bx, y - by, z) - 6.0*f(x - 2*bx, y - 2*by, z) - + 4.0*f(x - 3*bx, y - 3*by, z) - f(x - 4*bx, y - 4*by, z); + // 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); } - // 5th order extrapolation to a point - template - void extrapolate5th(T &f, int x, int bx, int y, int by, int z) { - f(x, y, z) = 5.0*f(x - bx, y - by, z) - 10.0*f(x - 2*bx, y - 2*by, z) - + 10.0*f(x - 3*bx, y - 3*by, z) - 5.0*f(x - 4*bx, y - 4*by, z) - + f(x - 5*bx, y - 5*by, z); - } +#endif +} - template - BoundaryOp* boundaryClone(BoundaryRegion* region, const list &args, - const std::map &keywords) { - verifyNumPoints(region, numpoints); - - std::shared_ptr newgen = nullptr; - BoutReal val = 0.; - if (!args.empty()) { - // First argument should be a value or expression - std::string expr = args.front(); - try { - val = stringToReal(expr); - } catch (const BoutException&) { - val = 0.; - newgen = FieldFactory::get()->parse(expr); - } +// 2nd order extrapolation to a point +template void extrapolate2nd(T &f, int x, int bx, int y, int by, int z) { + f(x, y, z) = 2 * f(x - bx, y - by, z) - f(x - 2 * bx, y - 2 * by, z); +} + +// 3rd order extrapolation to a point +template void extrapolate3rd(T &f, int x, int bx, int y, int by, int z) { + f(x, y, z) = 3.0 * f(x - bx, y - by, z) - 3.0 * f(x - 2 * bx, y - 2 * by, z) + + f(x - 3 * bx, y - 3 * by, z); +} + +// 4th order extrapolation to a point +template void extrapolate4th(T &f, int x, int bx, int y, int by, int z) { + f(x, y, z) = 4.0 * f(x - bx, y - by, z) - 6.0 * f(x - 2 * bx, y - 2 * by, z) + + 4.0 * f(x - 3 * bx, y - 3 * by, z) - f(x - 4 * bx, y - 4 * by, z); +} + +// 5th order extrapolation to a point +template void extrapolate5th(T &f, int x, int bx, int y, int by, int z) { + f(x, y, z) = 5.0 * f(x - bx, y - by, z) - 10.0 * f(x - 2 * bx, y - 2 * by, z) + + 10.0 * f(x - 3 * bx, y - 3 * by, z) - 5.0 * f(x - 4 * bx, y - 4 * by, z) + + f(x - 5 * bx, y - 5 * by, z); +} + +template +BoundaryOp *boundaryClone(BoundaryRegion *region, const list &args, + const std::map &keywords) { + verifyNumPoints(region, numpoints); + + std::shared_ptr newgen = nullptr; + BoutReal val = 0.; + if (!args.empty()) { + // First argument should be a value or expression + std::string expr = args.front(); + try { + val = stringToReal(expr); + } catch (const BoutException&) { + val = 0.; + newgen = FieldFactory::get()->parse(expr); } - int width = region->width; - for (const auto &it : keywords) { - if (it.first == "width") { - width = stringToInt(it.second); - } else { - throw BoutException("Unrecognized boundary condition keyword %s for %s boundary", it.first.c_str(), region->label.c_str()); - } + } + int width = region->width; + for (const auto &it : keywords) { + if (it.first == "width") { + width = stringToInt(it.second); + } else { + throw BoutException("Unrecognized boundary condition keyword %s for %s boundary", + it.first.c_str(), region->label.c_str()); } - return new T(region, val, newgen, width); } + return new T(region, val, newgen, width); +} - template - BoundaryOp* boundaryCloneNoArguments(BoundaryRegion* region, const list &args, - const std::map &keywords) { - verifyNumPoints(region, numpoints); +template +BoundaryOp *boundaryCloneNoArguments(BoundaryRegion *region, const list &args, + const std::map &keywords) { + verifyNumPoints(region, numpoints); - if (!args.empty()) { - output << "WARNING: Ignoring arguments to BoundaryOp for "<label<<" region\n"; - } - int width = region->width; - for (const auto &it : keywords) { - if (it.first == "width") { - width = stringToInt(it.second); - } else { - throw BoutException("Unrecognized boundary condition keyword %s for %s boundary", it.first.c_str(), region->label.c_str()); - } + if (!args.empty()) { + output << "WARNING: Ignoring arguments to BoundaryOp for " << region->label + << " region\n"; + } + int width = region->width; + for (const auto &it : keywords) { + if (it.first == "width") { + width = stringToInt(it.second); + } else { + throw BoutException("Unrecognized boundary condition keyword %s for %s boundary", + it.first.c_str(), region->label.c_str()); } - return new T(region, width); } + return new T(region, width); +} } /////////////////////////////////////////////////////////////// @@ -181,16 +187,12 @@ namespace { // Included here so it's in the same 'translation unit' as the implementations, // so will be instantiated for each 'Derived'. -template -template +template +template void BoundaryOpWithApply::applyTemplate(T &f, BoutReal t) { - // Convert the pointer to have the type of the final implementation class, so - // we can use the single-point methods directly - //Derived* this_derived = (Derived*) this; - - Mesh* localmesh = f.getMesh(); - Coordinates* metric = f.getCoordinates(); + Mesh *localmesh = f.getMesh(); + Coordinates *metric = f.getCoordinates(); CELL_LOC loc = f.getLocation(); @@ -199,7 +201,7 @@ void BoundaryOpWithApply::applyTemplate(T &f, BoutReal t) int nz = f.getNz(); // Decide which generator to use - std::shared_ptr fg = gen; + std::shared_ptr fg = gen; if (!fg) { fg = f.getBndryGenerator(bndry->location); } @@ -209,121 +211,137 @@ void BoundaryOpWithApply::applyTemplate(T &f, BoutReal t) if (loc == CELL_CENTRE) { // no staggering - 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 (; !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 - BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) // In the guard cell - + localmesh->GlobalY(bndry->y - bndry->by) ); // 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; if (needs_delta) { - delta = bndry->bx*metric->dx(bndry->x, bndry->y) + bndry->by*metric->dy(bndry->x, bndry->y); + delta = bndry->bx * metric->dx(bndry->x, bndry->y) + + bndry->by * metric->dy(bndry->x, bndry->y); } else { delta = 0.; } - for(int z=0; zgenerate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + BoutReal znorm = BoutReal(z) / BoutReal(nz); + generated_val = fg->generate(xnorm, TWOPI * ynorm, TWOPI * znorm, t); - Derived::applyAtPoint(f, generated_val, bndry->x, bndry->bx, bndry->y, bndry->by, z, delta); + Derived::applyAtPoint(f, generated_val, bndry->x, bndry->bx, bndry->y, + bndry->by, z, delta); } - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + // Need to set second guard cell, as may be used for interpolation or upwinding + // derivatives for (int i = 1; i < width; i++) { - int x = bndry->x + i*bndry->bx; - int y = bndry->y + i*bndry->by; - for(int z=0; zx + i * bndry->bx; + int y = bndry->y + i * bndry->by; + for (int z = 0; z < nz; z++) { Derived::extrapolateFurther(f, x, bndry->bx, y, bndry->by, z); } } } - } - else if (loc == CELL_XLOW) { + } else 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) ); + 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); BoutReal delta; if (needs_delta) { - delta = bndry->bx*metric->dx(bndry->x, bndry->y) + bndry->by*metric->dy(bndry->x, bndry->y); + delta = bndry->bx * metric->dx(bndry->x, bndry->y) + + bndry->by * metric->dy(bndry->x, bndry->y); } else { delta = 0.; } - for(int z=0; zgenerate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + for (int z = 0; z < nz; z++) { + BoutReal znorm = BoutReal(z) / BoutReal(nz); + generated_val = fg->generate(xnorm, TWOPI * ynorm, TWOPI * znorm, t); - Derived::applyAtPointStaggered(f, generated_val, bndry->x, bndry->bx, bndry->y, 0, z, delta); + Derived::applyAtPointStaggered(f, generated_val, bndry->x, bndry->bx, + bndry->y, 0, z, delta); - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + // Need to set second guard cell, as may be used for interpolation or + // upwinding derivatives for (int i = 1; i < width; i++) { - int x = bndry->x + i*bndry->bx; + int x = bndry->x + i * bndry->bx; Derived::extrapolateFurther(f, x, bndry->bx, bndry->y, 0, z); } } } } else if (bndry->bx < 0) { // Inner x boundary. Set one point inwards - for(; !bndry->isDone(); bndry->next1d()) { + for (; !bndry->isDone(); bndry->next1d()) { - BoutReal xnorm = 0.5*( localmesh->GlobalX(bndry->x) - + localmesh->GlobalX(bndry->x - bndry->bx) ); + BoutReal xnorm = 0.5 * (localmesh->GlobalX(bndry->x) + + localmesh->GlobalX(bndry->x - bndry->bx)); BoutReal ynorm = localmesh->GlobalY(bndry->y); BoutReal delta; if (needs_delta) { - delta = bndry->bx*metric->dx(bndry->x + 1, bndry->y) + bndry->by*metric->dy(bndry->x + 1, bndry->y); + delta = bndry->bx * metric->dx(bndry->x + 1, bndry->y) + + bndry->by * metric->dy(bndry->x + 1, bndry->y); } else { delta = 0.; } - for(int z=0; zgenerate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + for (int z = 0; z < nz; z++) { + BoutReal znorm = BoutReal(z) / BoutReal(nz); + generated_val = fg->generate(xnorm, TWOPI * ynorm, TWOPI * znorm, t); // Set one point inwards - Derived::applyAtPointStaggered(f, generated_val, bndry->x + 1, bndry->bx, bndry->y, 0, z, delta); + Derived::applyAtPointStaggered(f, generated_val, bndry->x + 1, bndry->bx, + bndry->y, 0, z, delta); - // Need to set second and third guard cells, as may be used for interpolation or upwinding derivatives + // Need to set second and third guard cells, as may be used for interpolation + // or upwinding derivatives for (int i = 0; i < width; i++) { - int x = bndry->x + i*bndry->bx; + int x = bndry->x + i * bndry->bx; Derived::extrapolateFurther(f, x, bndry->bx, bndry->y, 0, z); } } } - } else if (bndry->by !=0) { + } else if (bndry->by != 0) { // y boundaries - for(; !bndry->isDone(); bndry->next1d()) { + for (; !bndry->isDone(); bndry->next1d()) { // x norm is shifted bndry->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 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; if (needs_delta) { - delta = bndry->bx*metric->dx(bndry->x, bndry->y) + bndry->by*metric->dy(bndry->x, bndry->y); + delta = bndry->bx * metric->dx(bndry->x, bndry->y) + + bndry->by * metric->dy(bndry->x, bndry->y); } else { delta = 0.; } - for(int z=0; zgenerate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + for (int z = 0; z < nz; z++) { + BoutReal znorm = BoutReal(z) / BoutReal(nz); + generated_val = fg->generate(xnorm, TWOPI * ynorm, TWOPI * znorm, t); - Derived::applyAtPoint(f, generated_val, bndry->x, 0, bndry->y, bndry->by, z, delta); + Derived::applyAtPoint(f, generated_val, bndry->x, 0, bndry->y, bndry->by, z, + delta); - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=1;iy + i*bndry->by; + // Need to set second guard cell, as may be used for interpolation or + // upwinding derivatives + for (int i = 1; i < width; i++) { + int y = bndry->y + i * bndry->by; Derived::extrapolateFurther(f, bndry->x, 0, y, bndry->by, z); } } @@ -333,82 +351,95 @@ void BoundaryOpWithApply::applyTemplate(T &f, BoutReal t) // Shifted in Y if (bndry->by > 0) { // Upper y boundary boundary - for(; !bndry->isDone(); bndry->next1d()) { + 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)); + BoutReal ynorm = 0.5 * (localmesh->GlobalY(bndry->y) + + localmesh->GlobalY(bndry->y - bndry->by)); BoutReal delta; if (needs_delta) { - delta = bndry->bx*metric->dx(bndry->x, bndry->y) + bndry->by*metric->dy(bndry->x, bndry->y); + delta = bndry->bx * metric->dx(bndry->x, bndry->y) + + bndry->by * metric->dy(bndry->x, bndry->y); } else { delta = 0.; } - for(int z=0; zgenerate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + for (int z = 0; z < nz; z++) { + BoutReal znorm = BoutReal(z) / BoutReal(nz); + generated_val = fg->generate(xnorm, TWOPI * ynorm, TWOPI * znorm, t); - Derived::applyAtPointStaggered(f, generated_val, bndry->x, 0, bndry->y, bndry->by, z, delta); + Derived::applyAtPointStaggered(f, generated_val, bndry->x, 0, bndry->y, + bndry->by, z, delta); - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=1;iy + i*bndry->by; + // Need to set second guard cell, as may be used for interpolation or + // upwinding derivatives + for (int i = 1; i < width; i++) { + int y = bndry->y + i * bndry->by; Derived::extrapolateFurther(f, bndry->x, 0, y, bndry->by, z); } } } } else if (bndry->by < 0) { // Lower y boundary. Set one point inwards - for(; !bndry->isDone(); bndry->next1d()) { + 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)); + BoutReal ynorm = 0.5 * (localmesh->GlobalY(bndry->y) + + localmesh->GlobalY(bndry->y - bndry->by)); BoutReal delta; if (needs_delta) { - delta = bndry->bx*metric->dx(bndry->x, bndry->y + 1) + bndry->by*metric->dy(bndry->x, bndry->y + 1); + delta = bndry->bx * metric->dx(bndry->x, bndry->y + 1) + + bndry->by * metric->dy(bndry->x, bndry->y + 1); } else { delta = 0.; } - for(int z=0; zgenerate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + for (int z = 0; z < nz; z++) { + BoutReal znorm = BoutReal(z) / BoutReal(nz); + generated_val = fg->generate(xnorm, TWOPI * ynorm, TWOPI * znorm, t); - Derived::applyAtPointStaggered(f, generated_val, bndry->x, 0, bndry->y+1, bndry->by, z, delta); + Derived::applyAtPointStaggered(f, generated_val, bndry->x, 0, bndry->y + 1, + bndry->by, z, delta); - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=0;iy + i*bndry->by; + // Need to set second guard cell, as may be used for interpolation or + // upwinding derivatives + for (int i = 0; i < width; i++) { + int y = bndry->y + i * bndry->by; Derived::extrapolateFurther(f, bndry->x, 0, y, bndry->by, z); } } } } else if (bndry->bx != 0) { // x boundaries - for(; !bndry->isDone(); bndry->next1d()) { + 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 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; if (needs_delta) { - delta = bndry->bx*metric->dx(bndry->x, bndry->y) + bndry->by*metric->dy(bndry->x, bndry->y); + delta = bndry->bx * metric->dx(bndry->x, bndry->y) + + bndry->by * metric->dy(bndry->x, bndry->y); } else { delta = 0.; } - for(int z=0; zgenerate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + for (int z = 0; z < nz; z++) { + BoutReal znorm = BoutReal(z) / BoutReal(nz); + generated_val = fg->generate(xnorm, TWOPI * ynorm, TWOPI * znorm, t); - Derived::applyAtPoint(f, generated_val, bndry->x, bndry->bx, bndry->y, 0, z, delta); + Derived::applyAtPoint(f, generated_val, bndry->x, bndry->bx, bndry->y, 0, z, + delta); - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=1;ix + i*bndry->bx; + // Need to set second guard cell, as may be used for interpolation or + // upwinding derivatives + for (int i = 1; i < width; i++) { + int x = bndry->x + i * bndry->bx; Derived::extrapolateFurther(f, x, bndry->bx, bndry->y, 0, z); } } @@ -416,32 +447,41 @@ void BoundaryOpWithApply::applyTemplate(T &f, BoutReal t) } } else if (loc == CELL_ZLOW) { // Staggered in Z. Note there are no z-boundaries. - 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 (; !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 - BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) // In the guard cell - + localmesh->GlobalY(bndry->y - bndry->by) ); // 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; if (needs_delta) { - delta = bndry->bx*metric->dx(bndry->x, bndry->y) + bndry->by*metric->dy(bndry->x, bndry->y); + delta = bndry->bx * metric->dx(bndry->x, bndry->y) + + bndry->by * metric->dy(bndry->x, bndry->y); } else { delta = 0.; } - for(int z=0; zgenerate should be periodic in z - BoutReal znorm = (BoutReal(z) - 0.5)/BoutReal(nz); // znorm is shifted by half a grid point because it is staggered - generated_val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + for (int z = 0; z < nz; z++) { + // It shouldn't matter if znorm<0 because the expression in fg->generate should + // be periodic in z + + // znorm is shifted by half a grid point because it is staggered + BoutReal znorm = (BoutReal(z) - 0.5) / BoutReal(nz); + generated_val = fg->generate(xnorm, TWOPI * ynorm, TWOPI * znorm, t); - Derived::applyAtPoint(f, generated_val, bndry->x, bndry->bx, bndry->y, bndry->by, z, delta); + Derived::applyAtPoint(f, generated_val, bndry->x, bndry->bx, bndry->y, + bndry->by, z, delta); - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + // Need to set second guard cell, as may be used for interpolation or upwinding + // derivatives for (int i = 1; i < width; i++) { - int x = bndry->x + i*bndry->bx; - int y = bndry->y + i*bndry->by; + int x = bndry->x + i * bndry->bx; + int y = bndry->y + i * bndry->by; Derived::extrapolateFurther(f, x, bndry->bx, y, bndry->by, z); } } @@ -450,87 +490,97 @@ void BoundaryOpWithApply::applyTemplate(T &f, BoutReal t) } else { if (loc == CELL_CENTRE) { // no staggering - for(; !bndry->isDone(); bndry->next1d()) { + for (; !bndry->isDone(); bndry->next1d()) { BoutReal delta; if (needs_delta) { - delta = bndry->bx*metric->dx(bndry->x, bndry->y) + bndry->by*metric->dy(bndry->x, bndry->y); + delta = bndry->bx * metric->dx(bndry->x, bndry->y) + + bndry->by * metric->dy(bndry->x, bndry->y); } else { delta = 0.; } - for(int z=0; zx, bndry->bx, bndry->y, bndry->by, z, delta); + for (int z = 0; z < nz; z++) { + Derived::applyAtPoint(f, val, bndry->x, bndry->bx, bndry->y, bndry->by, z, + delta); } - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + // Need to set second guard cell, as may be used for interpolation or upwinding + // derivatives for (int i = 1; i < width; i++) { - int x = bndry->x + i*bndry->bx; - int y = bndry->y + i*bndry->by; - for(int z=0; zx + i * bndry->bx; + int y = bndry->y + i * bndry->by; + for (int z = 0; z < nz; z++) { Derived::extrapolateFurther(f, x, bndry->bx, y, bndry->by, z); } } } - } - else if (loc == CELL_XLOW) { + } else if (loc == CELL_XLOW) { // field is shifted in X if (bndry->bx > 0) { // Outer x boundary - for(; !bndry->isDone(); bndry->next1d()) { + for (; !bndry->isDone(); bndry->next1d()) { BoutReal delta; if (needs_delta) { - delta = bndry->bx*metric->dx(bndry->x, bndry->y) + bndry->by*metric->dy(bndry->x, bndry->y); + delta = bndry->bx * metric->dx(bndry->x, bndry->y) + + bndry->by * metric->dy(bndry->x, bndry->y); } else { delta = 0.; } - for(int z=0; zx, bndry->bx, bndry->y, 0, z, delta); + for (int z = 0; z < nz; z++) { + Derived::applyAtPointStaggered(f, val, bndry->x, bndry->bx, bndry->y, 0, z, + delta); - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + // Need to set second guard cell, as may be used for interpolation or + // upwinding derivatives for (int i = 1; i < width; i++) { - int x = bndry->x + i*bndry->bx; + int x = bndry->x + i * bndry->bx; Derived::extrapolateFurther(f, x, bndry->bx, bndry->y, 0, z); } } } } else if (bndry->bx < 0) { // Inner x boundary. Set one point inwards - for(; !bndry->isDone(); bndry->next1d()) { + for (; !bndry->isDone(); bndry->next1d()) { BoutReal delta; if (needs_delta) { - delta = bndry->bx*metric->dx(bndry->x + 1, bndry->y) + bndry->by*metric->dy(bndry->x + 1, bndry->y); + delta = bndry->bx * metric->dx(bndry->x + 1, bndry->y) + + bndry->by * metric->dy(bndry->x + 1, bndry->y); } else { delta = 0.; } - for(int z=0; zx + 1, bndry->bx, bndry->y, 0, z, delta); + Derived::applyAtPointStaggered(f, val, bndry->x + 1, bndry->bx, bndry->y, 0, + z, delta); - // Need to set second and third guard cells, as may be used for interpolation or upwinding derivatives + // Need to set second and third guard cells, as may be used for interpolation + // or upwinding derivatives for (int i = 0; i < width; i++) { - int x = bndry->x + i*bndry->bx; + int x = bndry->x + i * bndry->bx; Derived::extrapolateFurther(f, x, bndry->bx, bndry->y, 0, z); } } } - } else if (bndry->by !=0) { + } else if (bndry->by != 0) { // y boundaries - for(; !bndry->isDone(); bndry->next1d()) { + for (; !bndry->isDone(); bndry->next1d()) { BoutReal delta; if (needs_delta) { - delta = bndry->bx*metric->dx(bndry->x, bndry->y) + bndry->by*metric->dy(bndry->x, bndry->y); + delta = bndry->bx * metric->dx(bndry->x, bndry->y) + + bndry->by * metric->dy(bndry->x, bndry->y); } else { delta = 0.; } - for(int z=0; zx, 0, bndry->y, bndry->by, z, delta); - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=1;iy + i*bndry->by; + // Need to set second guard cell, as may be used for interpolation or + // upwinding derivatives + for (int i = 1; i < width; i++) { + int y = bndry->y + i * bndry->by; Derived::extrapolateFurther(f, bndry->x, 0, y, bndry->by, z); } } @@ -540,61 +590,69 @@ void BoundaryOpWithApply::applyTemplate(T &f, BoutReal t) // Shifted in Y if (bndry->by > 0) { // Upper y boundary boundary - for(; !bndry->isDone(); bndry->next1d()) { + for (; !bndry->isDone(); bndry->next1d()) { BoutReal delta; if (needs_delta) { - delta = bndry->bx*metric->dx(bndry->x, bndry->y) + bndry->by*metric->dy(bndry->x, bndry->y); + delta = bndry->bx * metric->dx(bndry->x, bndry->y) + + bndry->by * metric->dy(bndry->x, bndry->y); } else { delta = 0.; } - for(int z=0; zx, 0, bndry->y, bndry->by, z, delta); + for (int z = 0; z < nz; z++) { + Derived::applyAtPointStaggered(f, val, bndry->x, 0, bndry->y, bndry->by, z, + delta); - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=1;iy + i*bndry->by; + // Need to set second guard cell, as may be used for interpolation or + // upwinding derivatives + for (int i = 1; i < width; i++) { + int y = bndry->y + i * bndry->by; Derived::extrapolateFurther(f, bndry->x, 0, y, bndry->by, z); } } } } else if (bndry->by < 0) { // Lower y boundary. Set one point inwards - for(; !bndry->isDone(); bndry->next1d()) { + for (; !bndry->isDone(); bndry->next1d()) { BoutReal delta; if (needs_delta) { - delta = bndry->bx*metric->dx(bndry->x, bndry->y + 1) + bndry->by*metric->dy(bndry->x, bndry->y + 1); + delta = bndry->bx * metric->dx(bndry->x, bndry->y + 1) + + bndry->by * metric->dy(bndry->x, bndry->y + 1); } else { delta = 0.; } - for(int z=0; zx, 0, bndry->y+1, bndry->by, z, delta); + for (int z = 0; z < nz; z++) { + Derived::applyAtPointStaggered(f, val, bndry->x, 0, bndry->y + 1, bndry->by, + z, delta); - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=0;iy + i*bndry->by; + // Need to set second guard cell, as may be used for interpolation or + // upwinding derivatives + for (int i = 0; i < width; i++) { + int y = bndry->y + i * bndry->by; Derived::extrapolateFurther(f, bndry->x, 0, y, bndry->by, z); } } } } else if (bndry->bx != 0) { // x boundaries - for(; !bndry->isDone(); bndry->next1d()) { + for (; !bndry->isDone(); bndry->next1d()) { BoutReal delta; if (needs_delta) { - delta = bndry->bx*metric->dx(bndry->x, bndry->y) + bndry->by*metric->dy(bndry->x, bndry->y); + delta = bndry->bx * metric->dx(bndry->x, bndry->y) + + bndry->by * metric->dy(bndry->x, bndry->y); } else { delta = 0.; } - for(int z=0; zx, bndry->bx, bndry->y, 0, z, delta); - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=1;ix + i*bndry->bx; + // Need to set second guard cell, as may be used for interpolation or + // upwinding derivatives + for (int i = 1; i < width; i++) { + int x = bndry->x + i * bndry->bx; Derived::extrapolateFurther(f, x, bndry->bx, bndry->y, 0, z); } } @@ -602,21 +660,24 @@ void BoundaryOpWithApply::applyTemplate(T &f, BoutReal t) } } else if (loc == CELL_ZLOW) { // Staggered in Z. Note there are no z-boundaries. - for(; !bndry->isDone(); bndry->next1d()) { + for (; !bndry->isDone(); bndry->next1d()) { BoutReal delta; if (needs_delta) { - delta = bndry->bx*metric->dx(bndry->x, bndry->y) + bndry->by*metric->dy(bndry->x, bndry->y); + delta = bndry->bx * metric->dx(bndry->x, bndry->y) + + bndry->by * metric->dy(bndry->x, bndry->y); } else { delta = 0.; } - for(int z=0; zx, bndry->bx, bndry->y, bndry->by, z, delta); + for (int z = 0; z < nz; z++) { + Derived::applyAtPoint(f, val, bndry->x, bndry->bx, bndry->y, bndry->by, z, + delta); - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + // Need to set second guard cell, as may be used for interpolation or upwinding + // derivatives for (int i = 1; i < width; i++) { - int x = bndry->x + i*bndry->bx; - int y = bndry->y + i*bndry->by; + int x = bndry->x + i * bndry->bx; + int y = bndry->y + i * bndry->by; Derived::extrapolateFurther(f, x, bndry->bx, y, bndry->by, z); } } @@ -627,20 +688,20 @@ void BoundaryOpWithApply::applyTemplate(T &f, BoutReal t) /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryDirichlet::clone(BoundaryRegion *region, const list &args, - const std::map &keywords) { +BoundaryOp *BoundaryDirichlet::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { return boundaryClone(region, args, keywords); } // Override apply(), using this private method to provide both Field2D and // Field3D versions, for BoundaryDirichlet because we apply a funny hack to the // extra guard cells -template -void BoundaryDirichlet::applyTemplate(T &f,BoutReal t) { - // Set (at 2nd order) the value at the mid-point between the guard cell and the grid cell to be val +template void BoundaryDirichlet::applyTemplate(T &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(); + Mesh *localmesh = f.getMesh(); // Check for staggered grids CELL_LOC loc = f.getLocation(); @@ -651,7 +712,7 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal t) { int nz = f.getNz(); // Decide which generator to use - std::shared_ptr fg = gen; + std::shared_ptr fg = gen; if (!fg) { fg = f.getBndryGenerator(bndry->location); } @@ -661,19 +722,23 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal t) { if (loc == CELL_CENTRE) { // Unstaggered case - 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 (; !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 - BoutReal ynorm = 0.5*( localmesh->GlobalY(bndry->y) // In the guard cell - + localmesh->GlobalY(bndry->y - bndry->by) ); // the grid cell + 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; zkgenerate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + for (int zk = 0; zk < nz; zk++) { + BoutReal znorm = BoutReal(zk) / BoutReal(nz); + generated_val = fg->generate(xnorm, TWOPI * ynorm, TWOPI * znorm, t); - f(bndry->x,bndry->y,zk) = 2*generated_val - f(bndry->x-bndry->bx, bndry->y-bndry->by, zk); + f(bndry->x, bndry->y, zk) = + 2 * generated_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 @@ -691,13 +756,17 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal t) { // this treatment for other boundary treatments, // i.e. elsewhere we tend to extrapolate. - // // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + // // Need to set second guard cell, as may be used for interpolation or + // upwinding derivatives // for(int i=1;ix + 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); - // // 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); + // f(xi, yi, zk) = 2*f(xi - bndry->bx, yi - bndry->by, zk) - f(xi - + // 2*bndry->bx, yi - 2*bndry->by, zk); + // // 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); // } } @@ -707,84 +776,93 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal t) { // can help with the stability of higher order methods. for (int i = 1; i < width; i++) { // 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; + int xi = bndry->x + i * bndry->bx; + int yi = bndry->y + i * bndry->by; xnorm = localmesh->GlobalX(xi); ynorm = localmesh->GlobalY(yi); - for(int zk=0; zkgenerate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + for (int zk = 0; zk < nz; zk++) { + BoutReal znorm = BoutReal(zk) / BoutReal(nz); + generated_val = fg->generate(xnorm, TWOPI * ynorm, TWOPI * znorm, t); f(xi, yi, zk) = generated_val; } } } - } else if(loc == CELL_XLOW) { + } else 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) ); + 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; zkgenerate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + for (int zk = 0; zk < nz; zk++) { + BoutReal znorm = BoutReal(zk) / BoutReal(nz); + generated_val = fg->generate(xnorm, TWOPI * ynorm, TWOPI * znorm, t); - f(bndry->x,bndry->y, zk) = generated_val; + f(bndry->x, bndry->y, zk) = generated_val; - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=1;ix + i*bndry->bx; - int yi = bndry->y ; + // Need to set second guard cell, as may be used for interpolation or + // upwinding derivatives + for (int i = 1; i < width; 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); + f(xi, yi, zk) = + 2 * f(xi - bndry->bx, yi, zk) - f(xi - 2 * bndry->bx, yi, zk); } } } } else 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) ); + 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; zkgenerate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + for (int zk = 0; zk < nz; zk++) { + BoutReal znorm = BoutReal(zk) / BoutReal(nz); + generated_val = fg->generate(xnorm, TWOPI * ynorm, TWOPI * znorm, t); f(bndry->x - bndry->bx, bndry->y, zk) = generated_val; - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=0;ix + i*bndry->bx; - int yi = bndry->y ; + // Need to set second guard cell, as may be used for interpolation or + // upwinding derivatives + for (int i = 0; i < width; 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); + f(xi, yi, zk) = + 2 * f(xi - bndry->bx, yi, zk) - f(xi - 2 * bndry->bx, yi, zk); } } } - } else if (bndry->by !=0) { + } else if (bndry->by != 0) { // y boundaries - for(; !bndry->isDone(); bndry->next1d()) { + for (; !bndry->isDone(); bndry->next1d()) { // x norm is shifted bndry->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 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; zkgenerate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + for (int zk = 0; zk < nz; zk++) { + BoutReal znorm = BoutReal(zk) / BoutReal(nz); + generated_val = fg->generate(xnorm, TWOPI * ynorm, TWOPI * znorm, t); - f(bndry->x, bndry->y, zk) = 2*generated_val - f(bndry->x-bndry->bx, bndry->y-bndry->by, zk); + f(bndry->x, bndry->y, zk) = + 2 * generated_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;ix ; - int yi = bndry->y + i*bndry->by; + // Need to set second guard cell, as may be used for interpolation or + // upwinding derivatives + for (int i = 1; i < width; 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); + f(xi, yi, zk) = + 2 * f(xi, yi - bndry->by, zk) - f(xi, yi - 2 * bndry->by, zk); } } } @@ -793,93 +871,113 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal t) { // Shifted in Y if (bndry->by > 0) { // Upper y boundary boundary - for(; !bndry->isDone(); bndry->next1d()) { + 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) ); + BoutReal ynorm = 0.5 * (localmesh->GlobalY(bndry->y) + + localmesh->GlobalY(bndry->y - bndry->by)); - for(int zk=0; zkgenerate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + for (int zk = 0; zk < nz; zk++) { + BoutReal znorm = BoutReal(zk) / BoutReal(nz); + generated_val = fg->generate(xnorm, TWOPI * ynorm, TWOPI * znorm, t); f(bndry->x, bndry->y, zk) = generated_val; - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=1;ix ; - int yi = bndry->y + i*bndry->by; + // Need to set second guard cell, as may be used for interpolation or + // upwinding derivatives + for (int i = 1; i < width; 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); + f(xi, yi, zk) = + 2.0 * f(xi, yi - bndry->by, zk) - f(xi, yi - 2 * bndry->by, zk); } } } } else if (bndry->by < 0) { // Lower y boundary. Set one point inwards - for(; !bndry->isDone(); bndry->next1d()) { + 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) ); + BoutReal ynorm = 0.5 * (localmesh->GlobalY(bndry->y) + + localmesh->GlobalY(bndry->y - bndry->by)); - for(int zk=0; zkgenerate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + for (int zk = 0; zk < nz; zk++) { + BoutReal znorm = BoutReal(zk) / BoutReal(nz); + generated_val = fg->generate(xnorm, TWOPI * ynorm, TWOPI * znorm, t); f(bndry->x, bndry->y - bndry->by, zk) = generated_val; - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=0;ix ; - int yi = bndry->y + i*bndry->by; + // Need to set second guard cell, as may be used for interpolation or + // upwinding derivatives + for (int i = 0; i < width; 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); + f(xi, yi, zk) = + 2 * f(xi, yi - bndry->by, zk) - f(xi, yi - 2 * bndry->by, zk); } } } } else if (bndry->bx != 0) { // x boundaries - for(; !bndry->isDone(); bndry->next1d()) { + 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 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; zkgenerate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); + for (int zk = 0; zk < nz; zk++) { + BoutReal znorm = BoutReal(zk) / BoutReal(nz); + generated_val = fg->generate(xnorm, TWOPI * ynorm, TWOPI * znorm, t); - f(bndry->x, bndry->y, zk) = 2*generated_val - f(bndry->x-bndry->bx, bndry->y-bndry->by, zk); + f(bndry->x, bndry->y, zk) = + 2 * generated_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;ix + i*bndry->bx; - int yi = bndry->y ; + // Need to set second guard cell, as may be used for interpolation or + // upwinding derivatives + for (int i = 1; i < width; 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); + f(xi, yi, zk) = + 2 * f(xi - bndry->bx, yi, zk) - f(xi - 2 * bndry->bx, yi, zk); } } } } } else if (loc == CELL_ZLOW) { // Staggered in Z. Note there are no z-boundaries. - 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 - - 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; zkgenerate should be periodic in z - BoutReal znorm = (BoutReal(zk) - 0.5)/BoutReal(nz); // znorm is shifted by half a grid point because it is staggered - generated_val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*znorm, t); - - f(bndry->x, bndry->y, zk) = 2*generated_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;ix + i*bndry->bx; - int yi = bndry->y ; + 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 + + 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; zk < nz; zk++) { + // It shouldn't matter if znorm<0 because the expression in fg->generate should + // be periodic in z + BoutReal znorm = + (BoutReal(zk) - 0.5) / + BoutReal( + nz); // znorm is shifted by half a grid point because it is staggered + generated_val = fg->generate(xnorm, TWOPI * ynorm, TWOPI * znorm, t); + + f(bndry->x, bndry->y, zk) = + 2 * generated_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; i < width; 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); + f(xi, yi, zk) = 2 * f(xi - bndry->bx, yi, zk) - f(xi - 2 * bndry->bx, yi, zk); } } } @@ -887,9 +985,10 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal t) { } else { if (loc == CELL_CENTRE) { // Unstaggered case - for(; !bndry->isDone(); bndry->next1d()) { - for(int zk=0; zkx, bndry->y, zk) = 2*val - f(bndry->x-bndry->bx, bndry->y-bndry->by, zk); + for (; !bndry->isDone(); bndry->next1d()) { + for (int zk = 0; zk < nz; zk++) { + 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 @@ -907,13 +1006,17 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal t) { // this treatment for other boundary treatments, // i.e. elsewhere we tend to extrapolate. - // // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + // // Need to set second guard cell, as may be used for interpolation or + // upwinding derivatives // for(int i=1;ix + 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); - // // 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); + // f(xi, yi, zk) = 2*f(xi - bndry->bx, yi - bndry->by, zk) - f(xi - + // 2*bndry->bx, yi - 2*bndry->by, zk); + // // 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); // } } @@ -923,57 +1026,64 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal t) { // can help with the stability of higher order methods. for (int i = 1; i < width; i++) { // 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; - for(int zk=0; zkx + i * bndry->bx; + int yi = bndry->y + i * bndry->by; + for (int zk = 0; zk < nz; zk++) { f(xi, yi, zk) = val; } } } - } else if(loc == CELL_XLOW) { + } else 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; zkisDone(); bndry->next1d()) { + for (int zk = 0; zk < nz; zk++) { 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;ix + i*bndry->bx; - int yi = bndry->y ; + // Need to set second guard cell, as may be used for interpolation or + // upwinding derivatives + for (int i = 1; i < width; 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); + f(xi, yi, zk) = + 2 * f(xi - bndry->bx, yi, zk) - f(xi - 2 * bndry->bx, yi, zk); } } } } else if (bndry->bx < 0) { // Inner x boundary. Set one point inwards - for(; !bndry->isDone(); bndry->next1d()) { - for(int zk=0; zkisDone(); bndry->next1d()) { + for (int zk = 0; zk < nz; zk++) { f(bndry->x - bndry->bx, bndry->y, zk) = val; - // Need to set second guard cell, as may be used for interpolation or upwinding derivatives - for(int i=0;ix + i*bndry->bx; - int yi = bndry->y ; + // Need to set second guard cell, as may be used for interpolation or + // upwinding derivatives + for (int i = 0; i < width; 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); + f(xi, yi, zk) = + 2 * f(xi - bndry->bx, yi, zk) - f(xi - 2 * bndry->bx, yi, zk); } } } - } else if (bndry->by !=0) { + } else if (bndry->by != 0) { // y boundaries - for(; !bndry->isDone(); bndry->next1d()) { - for(int zk=0; zkx, bndry->y, zk) = 2*val - f(bndry->x-bndry->bx, bndry->y-bndry->by, zk); + for (; !bndry->isDone(); bndry->next1d()) { + for (int zk = 0; zk < nz; zk++) { + 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;ix ; - int yi = bndry->y + i*bndry->by; + // Need to set second guard cell, as may be used for interpolation or + // upwinding derivatives + for (int i = 1; i < width; 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); + f(xi, yi, zk) = + 2 * f(xi, yi - bndry->by, zk) - f(xi, yi - 2 * bndry->by, zk); } } } @@ -982,62 +1092,71 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal t) { // Shifted in Y if (bndry->by > 0) { // Upper y boundary boundary - for(; !bndry->isDone(); bndry->next1d()) { - for(int zk=0; zkisDone(); bndry->next1d()) { + for (int zk = 0; zk < nz; zk++) { 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;ix ; - int yi = bndry->y + i*bndry->by; + // Need to set second guard cell, as may be used for interpolation or + // upwinding derivatives + for (int i = 1; i < width; 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); + f(xi, yi, zk) = + 2.0 * f(xi, yi - bndry->by, zk) - f(xi, yi - 2 * bndry->by, zk); } } } } else if (bndry->by < 0) { // Lower y boundary. Set one point inwards - for(; !bndry->isDone(); bndry->next1d()) { - for(int zk=0; zkisDone(); bndry->next1d()) { + for (int zk = 0; zk < nz; zk++) { 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;ix ; - int yi = bndry->y + i*bndry->by; + // Need to set second guard cell, as may be used for interpolation or + // upwinding derivatives + for (int i = 0; i < width; 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); + f(xi, yi, zk) = + 2 * f(xi, yi - bndry->by, zk) - f(xi, yi - 2 * bndry->by, zk); } } } } else if (bndry->bx != 0) { // x boundaries - for(; !bndry->isDone(); bndry->next1d()) { - for(int zk=0; zkx, bndry->y, zk) = 2*val - f(bndry->x-bndry->bx, bndry->y-bndry->by, zk); + for (; !bndry->isDone(); bndry->next1d()) { + for (int zk = 0; zk < nz; zk++) { + 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;ix + i*bndry->bx; - int yi = bndry->y ; + // Need to set second guard cell, as may be used for interpolation or + // upwinding derivatives + for (int i = 1; i < width; 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); + f(xi, yi, zk) = + 2 * f(xi - bndry->bx, yi, zk) - f(xi - 2 * bndry->bx, yi, zk); } } } } } else if (loc == CELL_ZLOW) { // Staggered in Z. Note there are no z-boundaries. - for(; !bndry->isDone(); bndry->next1d()) { - for(int zk=0; zkx, bndry->y, zk) = 2*val - f(bndry->x-bndry->bx, bndry->y-bndry->by, zk); + for (; !bndry->isDone(); bndry->next1d()) { + for (int zk = 0; zk < nz; zk++) { + 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;ix + i*bndry->bx; - int yi = bndry->y ; + // Need to set second guard cell, as may be used for interpolation or upwinding + // derivatives + for (int i = 1; i < width; 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); + f(xi, yi, zk) = 2 * f(xi - bndry->bx, yi, zk) - f(xi - 2 * bndry->bx, yi, zk); } } } @@ -1048,164 +1167,244 @@ void BoundaryDirichlet::applyTemplate(T &f,BoutReal t) { /////////////////////////////////////////////////////////////// // New implementation, accurate to higher order -BoundaryOp* BoundaryDirichlet_O3::clone(BoundaryRegion *region, const list &args, - const std::map &keywords) { +BoundaryOp * +BoundaryDirichlet_O3::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { return boundaryClone(region, args, keywords); } -inline void BoundaryDirichlet_O3::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { - f(x, y, z) = (8./3)*val - 2.*f(x - bx, y - by, z) + f(x - 2*bx, y - 2*by, z)/3.; +inline void BoundaryDirichlet_O3::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, + int y, int by, int z, + BoutReal UNUSED(delta)) { + f(x, y, z) = + (8. / 3) * val - 2. * f(x - bx, y - by, z) + f(x - 2 * bx, y - 2 * by, z) / 3.; } -inline void BoundaryDirichlet_O3::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { - f(x, y, z) = (8./3)*val - 2.*f(x - bx, y - by, z) + f(x - 2*bx, y - 2*by, z)/3.; +inline void BoundaryDirichlet_O3::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, + int y, int by, int z, + BoutReal UNUSED(delta)) { + f(x, y, z) = + (8. / 3) * val - 2. * f(x - bx, y - by, z) + f(x - 2 * bx, y - 2 * by, z) / 3.; } -inline void BoundaryDirichlet_O3::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { +inline void BoundaryDirichlet_O3::applyAtPointStaggered(Field2D &f, BoutReal val, int x, + int UNUSED(bx), int y, + int UNUSED(by), int z, + BoutReal UNUSED(delta)) { f(x, y, z) = val; } -inline void BoundaryDirichlet_O3::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { +inline void BoundaryDirichlet_O3::applyAtPointStaggered(Field3D &f, BoutReal val, int x, + int UNUSED(bx), int y, + int UNUSED(by), int z, + BoutReal UNUSED(delta)) { f(x, y, z) = val; } -inline void BoundaryDirichlet_O3::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryDirichlet_O3::extrapolateFurther(Field2D &f, int x, int bx, int y, + int by, int z) { extrapolate3rd(f, x, bx, y, by, z); } -inline void BoundaryDirichlet_O3::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryDirichlet_O3::extrapolateFurther(Field3D &f, int x, int bx, int y, + int by, int z) { extrapolate3rd(f, x, bx, y, by, z); } /////////////////////////////////////////////////////////////// // Extrapolate to calculate boundary cell to 4th-order -BoundaryOp* BoundaryDirichlet_O4::clone(BoundaryRegion *region, const list &args, - const std::map &keywords) { +BoundaryOp * +BoundaryDirichlet_O4::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { return boundaryClone(region, args, keywords); } -inline void BoundaryDirichlet_O4::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { - f(x, y, z) = (16./5)*val - 3.*f(x - bx, y - by, z) + f(x - 2*bx, y - 2*by, z) - (1./5)*f(x - 3*bx, y - 3*by, z); +inline void BoundaryDirichlet_O4::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, + int y, int by, int z, + BoutReal UNUSED(delta)) { + f(x, y, z) = (16. / 5) * val - 3. * f(x - bx, y - by, z) + + f(x - 2 * bx, y - 2 * by, z) - (1. / 5) * f(x - 3 * bx, y - 3 * by, z); } -inline void BoundaryDirichlet_O4::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { - f(x, y, z) = (16./5)*val - 3.*f(x - bx, y - by, z) + f(x - 2*bx, y - 2*by, z) - (1./5)*f(x - 3*bx, y - 3*by, z); +inline void BoundaryDirichlet_O4::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, + int y, int by, int z, + BoutReal UNUSED(delta)) { + f(x, y, z) = (16. / 5) * val - 3. * f(x - bx, y - by, z) + + f(x - 2 * bx, y - 2 * by, z) - (1. / 5) * f(x - 3 * bx, y - 3 * by, z); } -inline void BoundaryDirichlet_O4::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { +inline void BoundaryDirichlet_O4::applyAtPointStaggered(Field2D &f, BoutReal val, int x, + int UNUSED(bx), int y, + int UNUSED(by), int z, + BoutReal UNUSED(delta)) { f(x, y, z) = val; } -inline void BoundaryDirichlet_O4::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { +inline void BoundaryDirichlet_O4::applyAtPointStaggered(Field3D &f, BoutReal val, int x, + int UNUSED(bx), int y, + int UNUSED(by), int z, + BoutReal UNUSED(delta)) { f(x, y, z) = val; } -inline void BoundaryDirichlet_O4::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryDirichlet_O4::extrapolateFurther(Field2D &f, int x, int bx, int y, + int by, int z) { extrapolate4th(f, x, bx, y, by, z); } -inline void BoundaryDirichlet_O4::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryDirichlet_O4::extrapolateFurther(Field3D &f, int x, int bx, int y, + int by, int z) { extrapolate4th(f, x, bx, y, by, z); } /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryDirichlet_smooth::clone(BoundaryRegion *region, const list &args, - const std::map &keywords) { +BoundaryOp * +BoundaryDirichlet_smooth::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { return boundaryClone(region, args, keywords); } -inline void BoundaryDirichlet_smooth::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { - f(x, y, z) = 5./3.*val - 0.5*f(x - bx, y - by, z) - 1./6.*f(x - 2*bx, y - 2*by, z); +inline void BoundaryDirichlet_smooth::applyAtPoint(Field2D &f, BoutReal val, int x, + int bx, int y, int by, int z, + BoutReal UNUSED(delta)) { + f(x, y, z) = + 5. / 3. * val - 0.5 * f(x - bx, y - by, z) - 1. / 6. * f(x - 2 * bx, y - 2 * by, z); } -inline void BoundaryDirichlet_smooth::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryDirichlet_smooth::applyAtPoint(Field3D &f, BoutReal val, int x, + int bx, int y, int by, int z, + BoutReal UNUSED(delta)) { // Dirichlet bc using val and first grid point would be // fb = 2*val - f0 // using val and second grid point would be // fb = 4/3*val - 1/3*f1 // Here we apply the bc using the average of the two, to try and suppress // grid-scale oscillations at the boundary - f(x, y, z) = 5./3.*val - 0.5*f(x - bx, y - by, z) - 1./6.*f(x - 2*bx, y - 2*by, z); + f(x, y, z) = + 5. / 3. * val - 0.5 * f(x - bx, y - by, z) - 1. / 6. * f(x - 2 * bx, y - 2 * by, z); } -inline void BoundaryDirichlet_smooth::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { +inline void BoundaryDirichlet_smooth::applyAtPointStaggered(Field2D &f, BoutReal val, + int x, int UNUSED(bx), int y, + int UNUSED(by), int z, + BoutReal UNUSED(delta)) { f(x, y, z) = val; } -inline void BoundaryDirichlet_smooth::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { +inline void BoundaryDirichlet_smooth::applyAtPointStaggered(Field3D &f, BoutReal val, + int x, int UNUSED(bx), int y, + int UNUSED(by), int z, + BoutReal UNUSED(delta)) { f(x, y, z) = val; } -inline void BoundaryDirichlet_smooth::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryDirichlet_smooth::extrapolateFurther(Field2D &f, int x, int bx, int y, + int by, int z) { extrapolate2nd(f, x, bx, y, by, z); } -inline void BoundaryDirichlet_smooth::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryDirichlet_smooth::extrapolateFurther(Field3D &f, int x, int bx, int y, + int by, int z) { extrapolate2nd(f, x, bx, y, by, z); } /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryDirichlet_2ndOrder::clone(BoundaryRegion *region, const list &args, - const std::map &keywords) { +BoundaryOp * +BoundaryDirichlet_2ndOrder::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { output << "WARNING: Use of boundary condition \"dirichlet_2ndorder\" is deprecated!\n"; output << " Consider using \"dirichlet\" instead\n"; return boundaryClone(region, args, keywords); } -// Set (at 2nd order) the value at the mid-point between the guard cell and the grid cell to be val +// 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 -inline void BoundaryDirichlet_2ndOrder::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { - f(x, y, z) = 8./3.*val - 2.*f(x - bx, y - by, z) + 1./3.*f(x - 2*bx, y - 2*by, z); -} -inline void BoundaryDirichlet_2ndOrder::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { - f(x, y, z) = 8./3.*val - 2.*f(x - bx, y - by, z) + 1./3.*f(x - 2*bx, y - 2*by, z); -} - -inline void BoundaryDirichlet_2ndOrder::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { +inline void BoundaryDirichlet_2ndOrder::applyAtPoint(Field2D &f, BoutReal val, int x, + int bx, int y, int by, int z, + BoutReal UNUSED(delta)) { + f(x, y, z) = + 8. / 3. * val - 2. * f(x - bx, y - by, z) + 1. / 3. * f(x - 2 * bx, y - 2 * by, z); +} +inline void BoundaryDirichlet_2ndOrder::applyAtPoint(Field3D &f, BoutReal val, int x, + int bx, int y, int by, int z, + BoutReal UNUSED(delta)) { + f(x, y, z) = + 8. / 3. * val - 2. * f(x - bx, y - by, z) + 1. / 3. * f(x - 2 * bx, y - 2 * by, z); +} + +inline void BoundaryDirichlet_2ndOrder::applyAtPointStaggered(Field2D &f, BoutReal val, + int x, int UNUSED(bx), + int y, int UNUSED(by), + int z, + BoutReal UNUSED(delta)) { f(x, y, z) = val; } -inline void BoundaryDirichlet_2ndOrder::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { +inline void BoundaryDirichlet_2ndOrder::applyAtPointStaggered(Field3D &f, BoutReal val, + int x, int UNUSED(bx), + int y, int UNUSED(by), + int z, + BoutReal UNUSED(delta)) { f(x, y, z) = val; } -inline void BoundaryDirichlet_2ndOrder::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryDirichlet_2ndOrder::extrapolateFurther(Field2D &f, int x, int bx, + int y, int by, int z) { extrapolate2nd(f, x, bx, y, by, z); } -inline void BoundaryDirichlet_2ndOrder::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryDirichlet_2ndOrder::extrapolateFurther(Field3D &f, int x, int bx, + int y, int by, int z) { extrapolate2nd(f, x, bx, y, by, z); } /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryDirichlet_O5::clone(BoundaryRegion *region, const list &args, - const std::map &keywords) { +BoundaryOp * +BoundaryDirichlet_O5::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { return boundaryClone(region, args, keywords); } -inline void BoundaryDirichlet_O5::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { - f(x, y, z) = 128./35.*val - 4.*f(x - bx, y - by, z) + 2.*f(x - 2*bx, y - 2*by, z) - 4./5.*f(x - 3*bx, y - 3*by, z) + 1./7.*f(x - 4*bx, y - 4*by, z); +inline void BoundaryDirichlet_O5::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, + int y, int by, int z, + BoutReal UNUSED(delta)) { + f(x, y, z) = + 128. / 35. * val - 4. * f(x - bx, y - by, z) + 2. * f(x - 2 * bx, y - 2 * by, z) - + 4. / 5. * f(x - 3 * bx, y - 3 * by, z) + 1. / 7. * f(x - 4 * bx, y - 4 * by, z); } -inline void BoundaryDirichlet_O5::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { - f(x, y, z) = 128./35.*val - 4.*f(x - bx, y - by, z) + 2.*f(x - 2*bx, y - 2*by, z) - 4./5.*f(x - 3*bx, y - 3*by, z) + 1./7.*f(x - 4*bx, y - 4*by, z); +inline void BoundaryDirichlet_O5::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, + int y, int by, int z, + BoutReal UNUSED(delta)) { + f(x, y, z) = + 128. / 35. * val - 4. * f(x - bx, y - by, z) + 2. * f(x - 2 * bx, y - 2 * by, z) - + 4. / 5. * f(x - 3 * bx, y - 3 * by, z) + 1. / 7. * f(x - 4 * bx, y - 4 * by, z); } -inline void BoundaryDirichlet_O5::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { +inline void BoundaryDirichlet_O5::applyAtPointStaggered(Field2D &f, BoutReal val, int x, + int UNUSED(bx), int y, + int UNUSED(by), int z, + BoutReal UNUSED(delta)) { f(x, y, z) = val; } -inline void BoundaryDirichlet_O5::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int UNUSED(bx), int y, int UNUSED(by), int z, BoutReal UNUSED(delta)) { +inline void BoundaryDirichlet_O5::applyAtPointStaggered(Field3D &f, BoutReal val, int x, + int UNUSED(bx), int y, + int UNUSED(by), int z, + BoutReal UNUSED(delta)) { f(x, y, z) = val; } -inline void BoundaryDirichlet_O5::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryDirichlet_O5::extrapolateFurther(Field2D &f, int x, int bx, int y, + int by, int z) { // Changing this extrapolation to not depend on val, so just using grid point // values. JTO 16/10/2018 extrapolate5th(f, x, bx, y, by, z); } -inline void BoundaryDirichlet_O5::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryDirichlet_O5::extrapolateFurther(Field3D &f, int x, int bx, int y, + int by, int z) { // Changing this extrapolation to not depend on val, so just using grid point // values. Not sure if this is the correct order... JTO 16/10/2018 extrapolate5th(f, x, bx, y, by, z); } - /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryNeumann_NonOrthogonal::clone(BoundaryRegion *region, const list &args, - const std::map &keywords) { +BoundaryOp * +BoundaryNeumann_NonOrthogonal::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { verifyNumPoints(region, 1); if (!args.empty()) { output << "WARNING: argument is set to BoundaryNeumann_NonOrthogonal\n"; @@ -1215,45 +1414,53 @@ BoundaryOp* BoundaryNeumann_NonOrthogonal::clone(BoundaryRegion *region, const l } if (!keywords.empty()) { // Given keywords, but not using - throw BoutException("Keywords ignored in boundary : %s", keywords.begin()->first.c_str()); + throw BoutException("Keywords ignored in boundary : %s", + keywords.begin()->first.c_str()); } return new BoundaryNeumann_NonOrthogonal(region); } -template +template void BoundaryNeumann_NonOrthogonal::applyTemplate(T &f, BoutReal UNUSED(t)) { - Mesh* localmesh = f.getMesh(); + Mesh *localmesh = f.getMesh(); Coordinates *metric = f.getCoordinates(); // Calculate derivatives for metric use localmesh->communicate(f); T dfdy = DDY(f); T dfdz = DDZ(f); // Loop over all elements and set equal to the next point in - for(bndry->first(); !bndry->isDone(); bndry->next1d()) { + for (bndry->first(); !bndry->isDone(); bndry->next1d()) { // Interpolate (linearly) metrics to halfway between last cell and boundary cell - BoutReal g11shift = 0.5*(metric->g11(bndry->x,bndry->y) + metric->g11(bndry->x-bndry->bx,bndry->y)); - BoutReal g12shift = 0.5*(metric->g12(bndry->x,bndry->y) + metric->g12(bndry->x-bndry->bx,bndry->y)); - BoutReal g13shift = 0.5*(metric->g13(bndry->x,bndry->y) + metric->g13(bndry->x-bndry->bx,bndry->y)); + BoutReal g11shift = 0.5 * (metric->g11(bndry->x, bndry->y) + + metric->g11(bndry->x - bndry->bx, bndry->y)); + BoutReal g12shift = 0.5 * (metric->g12(bndry->x, bndry->y) + + metric->g12(bndry->x - bndry->bx, bndry->y)); + BoutReal g13shift = 0.5 * (metric->g13(bndry->x, bndry->y) + + metric->g13(bndry->x - bndry->bx, bndry->y)); // 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++) { - BoutReal xshift = g12shift*dfdy(bndry->x-bndry->bx,bndry->y,z) - + g13shift*dfdz(bndry->x-bndry->bx,bndry->y,z); + for (int z = 0; z < localmesh->LocalNz; 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) { // x boundaries only - BoutReal delta = bndry->bx*metric->dx(bndry->x, bndry->y); - f(bndry->x, bndry->y, z) = f(bndry->x - bndry->bx, bndry->y, z) + delta/g11shift*(val - xshift); + BoutReal delta = bndry->bx * metric->dx(bndry->x, bndry->y); + f(bndry->x, bndry->y, z) = + f(bndry->x - bndry->bx, bndry->y, z) + delta / g11shift * (val - xshift); if (width == 2) { - f(bndry->x + bndry->bx, bndry->y, z) = f(bndry->x - 2*bndry->bx, bndry->y, z) + 3.0*delta/g11shift*(val - xshift); + f(bndry->x + bndry->bx, bndry->y, z) = + f(bndry->x - 2 * bndry->bx, bndry->y, z) + + 3.0 * delta / g11shift * (val - xshift); } } else if (bndry->by != 0 && bndry->bx == 0) { // y boundaries only // no need to shift this b/c we want parallel nuemann not theta - BoutReal delta = bndry->by*metric->dy(bndry->x, bndry->y); - f(bndry->x, bndry->y, z) = f(bndry->x, bndry->y - bndry->by, z) + delta*val; + BoutReal delta = bndry->by * metric->dy(bndry->x, bndry->y); + f(bndry->x, bndry->y, z) = f(bndry->x, bndry->y - bndry->by, z) + delta * val; if (width == 2) { - f(bndry->x, bndry->y + bndry->by, z) = f(bndry->x, bndry->y - 2*bndry->by, z) + 3.0*delta*val; + f(bndry->x, bndry->y + bndry->by, z) = + f(bndry->x, bndry->y - 2 * bndry->by, z) + 3.0 * delta * val; } } else { // set corners to zero @@ -1268,235 +1475,316 @@ void BoundaryNeumann_NonOrthogonal::applyTemplate(T &f, BoutReal UNUSED(t)) { /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryNeumann2::clone(BoundaryRegion *region, const list &args, - const std::map &keywords) { +BoundaryOp *BoundaryNeumann2::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { output << "WARNING: Use of boundary condition \"neumann2\" is deprecated!\n"; output << " Consider using \"neumann\" instead\n"; return boundaryCloneNoArguments(region, args, keywords); } -inline void BoundaryNeumann2::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { - f(x, y, z) = (4.*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z))/3.; +inline void BoundaryNeumann2::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, + int bx, int y, int by, int z, + BoutReal UNUSED(delta)) { + f(x, y, z) = (4. * f(x - bx, y - by, z) - f(x - 2 * bx, y - 2 * by, z)) / 3.; } -inline void BoundaryNeumann2::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { - f(x, y, z) = (4.*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z))/3.; +inline void BoundaryNeumann2::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, + int bx, int y, int by, int z, + BoutReal UNUSED(delta)) { + f(x, y, z) = (4. * f(x - bx, y - by, z) - f(x - 2 * bx, y - 2 * by, z)) / 3.; } -void BoundaryNeumann2::applyAtPointStaggered(Field2D &UNUSED(f), BoutReal UNUSED(val), int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), BoutReal UNUSED(delta)) { +void BoundaryNeumann2::applyAtPointStaggered(Field2D &UNUSED(f), BoutReal UNUSED(val), + int UNUSED(x), int UNUSED(bx), int UNUSED(y), + int UNUSED(by), int UNUSED(z), + BoutReal UNUSED(delta)) { throw BoutException("BoundaryNeumann2 not implemented for staggered grids"); } -void BoundaryNeumann2::applyAtPointStaggered(Field3D &UNUSED(f), BoutReal UNUSED(val), int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), BoutReal UNUSED(delta)) { +void BoundaryNeumann2::applyAtPointStaggered(Field3D &UNUSED(f), BoutReal UNUSED(val), + int UNUSED(x), int UNUSED(bx), int UNUSED(y), + int UNUSED(by), int UNUSED(z), + BoutReal UNUSED(delta)) { throw BoutException("BoundaryNeumann2 not implemented for staggered grids"); } -inline void BoundaryNeumann2::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryNeumann2::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, + int z) { extrapolate2nd(f, x, bx, y, by, z); } -inline void BoundaryNeumann2::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryNeumann2::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, + int z) { extrapolate2nd(f, x, bx, y, by, z); } /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryNeumann_2ndOrder::clone(BoundaryRegion *region, const list &args, - const std::map &keywords) { +BoundaryOp * +BoundaryNeumann_2ndOrder::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { output << "WARNING: Use of boundary condition \"neumann_2ndorder\" is deprecated!\n"; output << " Consider using \"neumann\" instead\n"; return boundaryClone(region, args, keywords); } -inline void BoundaryNeumann_2ndOrder::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { - f(x, y, z) = f(x - bx, y - by, z) + val*delta; +inline void BoundaryNeumann_2ndOrder::applyAtPoint(Field2D &f, BoutReal val, int x, + int bx, int y, int by, int z, + BoutReal delta) { + f(x, y, z) = f(x - bx, y - by, z) + val * delta; } -inline void BoundaryNeumann_2ndOrder::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { - f(x, y, z) = f(x - bx, y - by, z) + val*delta; +inline void BoundaryNeumann_2ndOrder::applyAtPoint(Field3D &f, BoutReal val, int x, + int bx, int y, int by, int z, + BoutReal delta) { + f(x, y, z) = f(x - bx, y - by, z) + val * delta; } -inline void BoundaryNeumann_2ndOrder::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { - f(x, y, z) = (4.*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z) + 2.*delta*val)/3.; +inline void BoundaryNeumann_2ndOrder::applyAtPointStaggered(Field2D &f, BoutReal val, + int x, int bx, int y, int by, + int z, BoutReal delta) { + f(x, y, z) = + (4. * f(x - bx, y - by, z) - f(x - 2 * bx, y - 2 * by, z) + 2. * delta * val) / 3.; } -inline void BoundaryNeumann_2ndOrder::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { - f(x, y, z) = (4.*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z) + 2.*delta*val)/3.; +inline void BoundaryNeumann_2ndOrder::applyAtPointStaggered(Field3D &f, BoutReal val, + int x, int bx, int y, int by, + int z, BoutReal delta) { + f(x, y, z) = + (4. * f(x - bx, y - by, z) - f(x - 2 * bx, y - 2 * by, z) + 2. * delta * val) / 3.; } -inline void BoundaryNeumann_2ndOrder::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryNeumann_2ndOrder::extrapolateFurther(Field2D &f, int x, int bx, int y, + int by, int z) { extrapolate2nd(f, x, bx, y, by, z); } -inline void BoundaryNeumann_2ndOrder::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryNeumann_2ndOrder::extrapolateFurther(Field3D &f, int x, int bx, int y, + int by, int z) { extrapolate2nd(f, x, bx, y, by, z); } - /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryNeumann::clone(BoundaryRegion *region, const list &args, - const std::map &keywords) { +BoundaryOp *BoundaryNeumann::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { return boundaryClone(region, args, keywords); } -inline void BoundaryNeumann::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { - f(x, y, z) = f(x - bx, y - by, z) + delta*val; +inline void BoundaryNeumann::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, + int by, int z, BoutReal delta) { + f(x, y, z) = f(x - bx, y - by, z) + delta * val; } -inline void BoundaryNeumann::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { - f(x, y, z) = f(x - bx, y - by, z) + delta*val; +inline void BoundaryNeumann::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, + int by, int z, BoutReal delta) { + f(x, y, z) = f(x - bx, y - by, z) + delta * val; } // For staggered case need to apply slightly differently Use one-sided // differencing. Cell is now on the boundary, so use one-sided differencing -inline void BoundaryNeumann::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { - f(x, y, z) = (4.*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z) + 2.*delta*val)/3.; +inline void BoundaryNeumann::applyAtPointStaggered(Field2D &f, BoutReal val, int x, + int bx, int y, int by, int z, + BoutReal delta) { + f(x, y, z) = + (4. * f(x - bx, y - by, z) - f(x - 2 * bx, y - 2 * by, z) + 2. * delta * val) / 3.; } -inline void BoundaryNeumann::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { - f(x, y, z) = (4.*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z) + 2.*delta*val)/3.; +inline void BoundaryNeumann::applyAtPointStaggered(Field3D &f, BoutReal val, int x, + int bx, int y, int by, int z, + BoutReal delta) { + f(x, y, z) = + (4. * f(x - bx, y - by, z) - f(x - 2 * bx, y - 2 * by, z) + 2. * delta * val) / 3.; } -inline void BoundaryNeumann::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryNeumann::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, + int z) { extrapolate2nd(f, x, bx, y, by, z); } -inline void BoundaryNeumann::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryNeumann::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, + int z) { extrapolate2nd(f, x, bx, y, by, z); } - - /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryNeumann_O4::clone(BoundaryRegion *region, const list &args, - const std::map &keywords) { +BoundaryOp * +BoundaryNeumann_O4::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { return boundaryClone(region, args, keywords); } -inline void BoundaryNeumann_O4::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { - f(x, y, z) = 12.*delta*val/11. + - ( 17.*f(x - bx, y - by, z) + 9.*f(x - 2*bx, y - 2*by, z) - - 5.*f(x - 3*bx, y - 3*by, z) + f(x - 4*bx, y - 4*by, z))/22.; -} -inline void BoundaryNeumann_O4::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { - f(x, y, z) = 12.*delta*val/11. + - ( 17.*f(x - bx, y - by, z) + 9.*f(x - 2*bx, y - 2*by, z) - - 5.*f(x - 3*bx, y - 3*by, z) + f(x - 4*bx, y - 4*by, z))/22.; -} - -inline void BoundaryNeumann_O4::applyAtPointStaggered(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { - f(x, y, z) = 12./25.*(delta*val - + 4.*f(x - bx, y - by, z) - 3.*f(x - 2*bx, y - 2*by, z) - + 4./3.*f(x - 3*bx, y - 3*by, z) - 1./4.*f(x - 4*bx, y - 4*by, z)); -} -inline void BoundaryNeumann_O4::applyAtPointStaggered(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { - f(x, y, z) = 12./25.*(delta*val - + 4.*f(x - bx, y - by, z) - 3.*f(x - 2*bx, y - 2*by, z) - + 4./3.*f(x - 3*bx, y - 3*by, z) - 1./4.*f(x - 4*bx, y - 4*by, z)); -} - -inline void BoundaryNeumann_O4::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryNeumann_O4::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, + int y, int by, int z, BoutReal delta) { + f(x, y, z) = 12. * delta * val / 11. + + (17. * f(x - bx, y - by, z) + 9. * f(x - 2 * bx, y - 2 * by, z) - + 5. * f(x - 3 * bx, y - 3 * by, z) + f(x - 4 * bx, y - 4 * by, z)) / + 22.; +} +inline void BoundaryNeumann_O4::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, + int y, int by, int z, BoutReal delta) { + f(x, y, z) = 12. * delta * val / 11. + + (17. * f(x - bx, y - by, z) + 9. * f(x - 2 * bx, y - 2 * by, z) - + 5. * f(x - 3 * bx, y - 3 * by, z) + f(x - 4 * bx, y - 4 * by, z)) / + 22.; +} + +inline void BoundaryNeumann_O4::applyAtPointStaggered(Field2D &f, BoutReal val, int x, + int bx, int y, int by, int z, + BoutReal delta) { + f(x, y, z) = + 12. / 25. * + (delta * val + 4. * f(x - bx, y - by, z) - 3. * f(x - 2 * bx, y - 2 * by, z) + + 4. / 3. * f(x - 3 * bx, y - 3 * by, z) - 1. / 4. * f(x - 4 * bx, y - 4 * by, z)); +} +inline void BoundaryNeumann_O4::applyAtPointStaggered(Field3D &f, BoutReal val, int x, + int bx, int y, int by, int z, + BoutReal delta) { + f(x, y, z) = + 12. / 25. * + (delta * val + 4. * f(x - bx, y - by, z) - 3. * f(x - 2 * bx, y - 2 * by, z) + + 4. / 3. * f(x - 3 * bx, y - 3 * by, z) - 1. / 4. * f(x - 4 * bx, y - 4 * by, z)); +} + +inline void BoundaryNeumann_O4::extrapolateFurther(Field2D &f, int x, int bx, int y, + int by, int z) { extrapolate5th(f, x, bx, y, by, z); } -inline void BoundaryNeumann_O4::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryNeumann_O4::extrapolateFurther(Field3D &f, int x, int bx, int y, + int by, int z) { extrapolate5th(f, x, bx, y, by, z); } /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryNeumann_4thOrder::clone(BoundaryRegion *region, const list &args, - const std::map &keywords) { +BoundaryOp * +BoundaryNeumann_4thOrder::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { return boundaryClone(region, args, keywords); } -inline void BoundaryNeumann_4thOrder::applyAtPoint(Field2D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { - f(x, y, z) = 12.*delta/11.*val + 17./22.*f(x - bx, y - by, z) + 9./22.*f(x - 2*bx, y - 2*by, z) - 5./22.*f(x - 3*bx, y - 3*by, z) + 1./22.*f(x - 4*bx, y - 4*by, z); -} -inline void BoundaryNeumann_4thOrder::applyAtPoint(Field3D &f, BoutReal val, int x, int bx, int y, int by, int z, BoutReal delta) { - f(x, y, z) = 12.*delta/11.*val + 17./22.*f(x - bx, y - by, z) + 9./22.*f(x - 2*bx, y - 2*by, z) - 5./22.*f(x - 3*bx, y - 3*by, z) + 1./22.*f(x - 4*bx, y - 4*by, z); -} - -void BoundaryNeumann_4thOrder::applyAtPointStaggered(Field2D &UNUSED(f), BoutReal UNUSED(val), int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), BoutReal UNUSED(delta)) { +inline void BoundaryNeumann_4thOrder::applyAtPoint(Field2D &f, BoutReal val, int x, + int bx, int y, int by, int z, + BoutReal delta) { + f(x, y, z) = 12. * delta / 11. * val + 17. / 22. * f(x - bx, y - by, z) + + 9. / 22. * f(x - 2 * bx, y - 2 * by, z) - + 5. / 22. * f(x - 3 * bx, y - 3 * by, z) + + 1. / 22. * f(x - 4 * bx, y - 4 * by, z); +} +inline void BoundaryNeumann_4thOrder::applyAtPoint(Field3D &f, BoutReal val, int x, + int bx, int y, int by, int z, + BoutReal delta) { + f(x, y, z) = 12. * delta / 11. * val + 17. / 22. * f(x - bx, y - by, z) + + 9. / 22. * f(x - 2 * bx, y - 2 * by, z) - + 5. / 22. * f(x - 3 * bx, y - 3 * by, z) + + 1. / 22. * f(x - 4 * bx, y - 4 * by, z); +} + +void BoundaryNeumann_4thOrder::applyAtPointStaggered(Field2D &UNUSED(f), + BoutReal UNUSED(val), int UNUSED(x), + int UNUSED(bx), int UNUSED(y), + int UNUSED(by), int UNUSED(z), + BoutReal UNUSED(delta)) { throw BoutException("BoundaryNeumann_4thOrder is not implemented for staggered grids."); } -void BoundaryNeumann_4thOrder::applyAtPointStaggered(Field3D &UNUSED(f), BoutReal UNUSED(val), int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), BoutReal UNUSED(delta)) { +void BoundaryNeumann_4thOrder::applyAtPointStaggered(Field3D &UNUSED(f), + BoutReal UNUSED(val), int UNUSED(x), + int UNUSED(bx), int UNUSED(y), + int UNUSED(by), int UNUSED(z), + BoutReal UNUSED(delta)) { throw BoutException("BoundaryNeumann_4thOrder is not implemented for staggered grids."); } -inline void BoundaryNeumann_4thOrder::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryNeumann_4thOrder::extrapolateFurther(Field2D &f, int x, int bx, int y, + int by, int z) { // Changing this extrapolation to not depend on val, so just using grid point // values. Previously was: - // f(x+bx,y+by,z) = -24.*delta*val + 27.*f(x,y,z) - 27.*f(x-bx,y-by,z) + f(x-2*bx,y-2*by,z); // The f(x-4*bx,y-4*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 + // f(x+bx,y+by,z) = -24.*delta*val + 27.*f(x,y,z) - 27.*f(x-bx,y-by,z) + + // f(x-2*bx,y-2*by,z); // The f(x-4*bx,y-4*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 // - JTO 16/10/2018 extrapolate5th(f, x, bx, y, by, z); } -inline void BoundaryNeumann_4thOrder::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryNeumann_4thOrder::extrapolateFurther(Field3D &f, int x, int bx, int y, + int by, int z) { // Changing this extrapolation to not depend on val, so just using grid point // values. Previously was - // f(x+bx,y+by,z) = -24.*delta*val + 27.*f(x,y,z) - 27.*f(x-bx,y-by,z) + f(x-2*bx,y-2*by,z); // The f(x-4*bx,y-4*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 + // f(x+bx,y+by,z) = -24.*delta*val + 27.*f(x,y,z) - 27.*f(x-bx,y-by,z) + + // f(x-2*bx,y-2*by,z); // The f(x-4*bx,y-4*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 // - JTO 16/10/2018 extrapolate5th(f, x, bx, y, by, z); } /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryNeumannPar::clone(BoundaryRegion *region, const list &args, - const std::map &keywords) { +BoundaryOp * +BoundaryNeumannPar::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { return boundaryCloneNoArguments(region, args, keywords); } -template -void BoundaryNeumannPar::applyTemplate(T &f, BoutReal UNUSED(t)) { - ASSERT1(f.getLocation() == CELL_CENTRE); // BoundaryNeumannPar not implemented for staggered fields +template void BoundaryNeumannPar::applyTemplate(T &f, BoutReal UNUSED(t)) { + ASSERT1(f.getLocation() == + CELL_CENTRE); // BoundaryNeumannPar not implemented for staggered fields Coordinates *metric = f.getCoordinates(); - for(bndry->first(); !bndry->isDone(); bndry->next()) - 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)); + for (bndry->first(); !bndry->isDone(); bndry->next()) + for (int z = 0; z < mesh->LocalNz; 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, - const std::map &keywords) { +BoundaryOp *BoundaryRobin::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { verifyNumPoints(region, 1); BoutReal a = 0.5, b = 1.0, g = 0.; - + list::const_iterator it = args.begin(); - + if (!keywords.empty()) { // Given keywords, but not using - throw BoutException("Keywords ignored in boundary : %s", keywords.begin()->first.c_str()); + throw BoutException("Keywords ignored in boundary : %s", + keywords.begin()->first.c_str()); } if (it != args.end()) { // First argument is 'a' a = stringToReal(*it); it++; - + if (it != args.end()) { // Second is 'b' b = stringToReal(*it); it++; - + if (it != args.end()) { - // Third is 'g' - g = stringToReal(*it); - it++; - if (it != args.end()) { - output << "WARNING: BoundaryRobin takes maximum of 3 arguments. Ignoring extras\n"; - } + // Third is 'g' + g = stringToReal(*it); + it++; + if (it != args.end()) { + output + << "WARNING: BoundaryRobin takes maximum of 3 arguments. Ignoring extras\n"; + } } } } - + return new BoundaryRobin(region, a, b, g); } -template -void BoundaryRobin::applyTemplate(T &f, BoutReal UNUSED(t)) { +template void BoundaryRobin::applyTemplate(T &f, BoutReal UNUSED(t)) { if (fabs(bval) < 1.e-12) { - for(bndry->first(); !bndry->isDone(); bndry->next()) - for(int z=0; zx, bndry->y, z) = gval / aval; - }else { - Coordinates* metric = f.getCoordinates(); - for(bndry->first(); !bndry->isDone(); bndry->next()) { - BoutReal delta = bndry->bx*metric->dx(bndry->x, bndry->y) + bndry->by*metric->dy(bndry->x, bndry->y); - for(int z=0; zx, bndry->y, z) = f(bndry->x - bndry->bx, bndry->y - bndry->by, z) + (gval - aval*f(bndry->x - bndry->bx, bndry->y - bndry->by, z) ) * delta / bval; + for (bndry->first(); !bndry->isDone(); bndry->next()) + for (int z = 0; z < f.getNz(); z++) + f(bndry->x, bndry->y, z) = gval / aval; + } else { + Coordinates *metric = f.getCoordinates(); + for (bndry->first(); !bndry->isDone(); bndry->next()) { + BoutReal delta = bndry->bx * metric->dx(bndry->x, bndry->y) + + bndry->by * metric->dy(bndry->x, bndry->y); + for (int z = 0; z < f.getNz(); z++) { + f(bndry->x, bndry->y, z) = + f(bndry->x - bndry->bx, bndry->y - bndry->by, z) + + (gval - aval * f(bndry->x - bndry->bx, bndry->y - bndry->by, z)) * delta / + bval; } } } @@ -1504,36 +1792,52 @@ void BoundaryRobin::applyTemplate(T &f, BoutReal UNUSED(t)) { /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryConstGradient::clone(BoundaryRegion *region, const list &args, - const std::map &keywords) { +BoundaryOp * +BoundaryConstGradient::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { return boundaryCloneNoArguments(region, args, keywords); } -inline void BoundaryConstGradient::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { - f(x, y, z) = 2.*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z); +inline void BoundaryConstGradient::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, + int bx, int y, int by, int z, + BoutReal UNUSED(delta)) { + f(x, y, z) = 2. * f(x - bx, y - by, z) - f(x - 2 * bx, y - 2 * by, z); } -inline void BoundaryConstGradient::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { - f(x, y, z) = 2.*f(x - bx, y - by, z) - f(x - 2*bx, y - 2*by, z); +inline void BoundaryConstGradient::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, + int bx, int y, int by, int z, + BoutReal UNUSED(delta)) { + f(x, y, z) = 2. * f(x - bx, y - by, z) - f(x - 2 * bx, y - 2 * by, z); } -void BoundaryConstGradient::applyAtPointStaggered(Field2D &UNUSED(f), BoutReal UNUSED(val), int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), BoutReal UNUSED(delta)) { +void BoundaryConstGradient::applyAtPointStaggered(Field2D &UNUSED(f), + BoutReal UNUSED(val), int UNUSED(x), + int UNUSED(bx), int UNUSED(y), + int UNUSED(by), int UNUSED(z), + BoutReal UNUSED(delta)) { throw BoutException("BoundaryConstGradient is not implemented for staggered grids."); } -void BoundaryConstGradient::applyAtPointStaggered(Field3D &UNUSED(f), BoutReal UNUSED(val), int UNUSED(x), int UNUSED(bx), int UNUSED(y), int UNUSED(by), int UNUSED(z), BoutReal UNUSED(delta)) { +void BoundaryConstGradient::applyAtPointStaggered(Field3D &UNUSED(f), + BoutReal UNUSED(val), int UNUSED(x), + int UNUSED(bx), int UNUSED(y), + int UNUSED(by), int UNUSED(z), + BoutReal UNUSED(delta)) { throw BoutException("BoundaryConstGradient is not implemented for staggered grids."); } -inline void BoundaryConstGradient::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryConstGradient::extrapolateFurther(Field2D &f, int x, int bx, int y, + int by, int z) { extrapolate2nd(f, x, bx, y, by, z); } -inline void BoundaryConstGradient::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryConstGradient::extrapolateFurther(Field3D &f, int x, int bx, int y, + int by, int z) { extrapolate2nd(f, x, bx, y, by, z); } /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryZeroLaplace::clone(BoundaryRegion *region, const list &args, - const std::map &keywords) { +BoundaryOp * +BoundaryZeroLaplace::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { return boundaryCloneNoArguments(region, args, keywords); } @@ -1541,26 +1845,28 @@ void BoundaryZeroLaplace::apply(Field2D &f, BoutReal UNUSED(t)) { Coordinates *metric = f.getCoordinates(); if ((bndry->location != BNDRY_XIN) && (bndry->location != BNDRY_XOUT)) { // Can't apply this boundary condition to non-X boundaries - throw BoutException("ERROR: Can't apply Zero Laplace condition to non-X boundaries\n"); + throw BoutException( + "ERROR: Can't apply Zero Laplace condition to non-X boundaries\n"); } // Constant X derivative int bx = bndry->bx; // Loop over the Y dimension - for(bndry->first(); !bndry->isDone(); bndry->nextY()) { + for (bndry->first(); !bndry->isDone(); bndry->nextY()) { int x = bndry->x; int y = bndry->y; - BoutReal g = (f(x-bx,y) - f(x-2*bx,y)) / metric->dx(x-bx,y); + BoutReal g = (f(x - bx, y) - f(x - 2 * bx, y)) / metric->dx(x - bx, y); // Loop in X towards edge of domain do { - f(x,y) = f(x-bx,y) + g*metric->dx(x,y); + f(x, y) = f(x - bx, y) + g * metric->dx(x, y); bndry->nextX(); - x = bndry->x; y = bndry->y; - }while(!bndry->isDone()); + x = bndry->x; + y = bndry->y; + } while (!bndry->isDone()); } } void BoundaryZeroLaplace::apply(Field3D &f, BoutReal UNUSED(t)) { - Mesh* localmesh = f.getMesh(); + Mesh *localmesh = f.getMesh(); int ncz = localmesh->LocalNz; @@ -1616,8 +1922,9 @@ void BoundaryZeroLaplace::apply(Field3D &f, BoutReal UNUSED(t)) { /////////////////////////////////////////////////////////////// -BoundaryOp *BoundaryZeroLaplace2::clone(BoundaryRegion *region, const list &args, - const std::map &keywords) { +BoundaryOp * +BoundaryZeroLaplace2::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { return boundaryCloneNoArguments(region, args, keywords); } @@ -1648,12 +1955,12 @@ void BoundaryZeroLaplace2::apply(Field2D &f, BoutReal UNUSED(t)) { } void BoundaryZeroLaplace2::apply(Field3D &f, BoutReal UNUSED(t)) { - Mesh* localmesh = f.getMesh(); + Mesh *localmesh = f.getMesh(); int ncz = localmesh->LocalNz; ASSERT0(ncz % 2 == 0); // Allocation assumes even number - + // allocate memory Array c0(ncz / 2 + 1), c1(ncz / 2 + 1), c2(ncz / 2 + 1); @@ -1702,76 +2009,81 @@ void BoundaryZeroLaplace2::apply(Field3D &f, BoutReal UNUSED(t)) { /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryConstLaplace::clone(BoundaryRegion *region, const list &args, - const std::map &keywords) { +BoundaryOp * +BoundaryConstLaplace::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { return boundaryCloneNoArguments(region, args, keywords); } void BoundaryConstLaplace::apply(Field2D &f, BoutReal UNUSED(t)) { if ((bndry->location != BNDRY_XIN) && (bndry->location != BNDRY_XOUT)) { // Can't apply this boundary condition to non-X boundaries - throw BoutException("ERROR: Can't apply Zero Laplace condition to non-X boundaries\n"); + throw BoutException( + "ERROR: Can't apply Zero Laplace condition to non-X boundaries\n"); } - + // Constant X second derivative int bx = bndry->bx; // Loop over the Y dimension - for(bndry->first(); !bndry->isDone(); bndry->nextY()) { + for (bndry->first(); !bndry->isDone(); bndry->nextY()) { int x = bndry->x; int y = bndry->y; // Calculate the Laplacian on the last point - dcomplex la,lb,lc; - laplace_tridag_coefs(x-2*bx, y, 0, la, lb, lc); - dcomplex val = la*f(x-bx-1,y) + lb*f(x-2*bx,y) + lc*f(x-2*bx+1,y); + dcomplex la, lb, lc; + laplace_tridag_coefs(x - 2 * bx, y, 0, la, lb, lc); + dcomplex val = + la * f(x - bx - 1, y) + lb * f(x - 2 * bx, y) + lc * f(x - 2 * bx + 1, y); // Loop in X towards edge of domain do { - laplace_tridag_coefs(x-bx, y, 0, la, lb, lc); + laplace_tridag_coefs(x - bx, y, 0, la, lb, lc); if (bx < 0) { // Lower X - f(x,y) = ((val - lb*f(x-bx,y) + lc*f(x-2*bx,y)) / la).real(); - }else // Upper X - f(x,y) = ((val - lb*f(x-bx,y) + la*f(x-2*bx,y)) / lc).real(); - + f(x, y) = ((val - lb * f(x - bx, y) + lc * f(x - 2 * bx, y)) / la).real(); + } else // Upper X + f(x, y) = ((val - lb * f(x - bx, y) + la * f(x - 2 * bx, y)) / lc).real(); + bndry->nextX(); - x = bndry->x; y = bndry->y; - }while(!bndry->isDone()); + x = bndry->x; + y = bndry->y; + } while (!bndry->isDone()); } } void BoundaryConstLaplace::apply(Field3D &f, BoutReal UNUSED(t)) { if ((bndry->location != BNDRY_XIN) && (bndry->location != BNDRY_XOUT)) { // Can't apply this boundary condition to non-X boundaries - throw BoutException("ERROR: Can't apply Zero Laplace condition to non-X boundaries\n"); + throw BoutException( + "ERROR: Can't apply Zero Laplace condition to non-X boundaries\n"); } - - Mesh* localmesh = f.getMesh(); + + Mesh *localmesh = f.getMesh(); Coordinates *metric = f.getCoordinates(); - + int ncz = localmesh->LocalNz; // Allocate memory - Array c0(ncz/2 + 1), c1(ncz/2 + 1), c2(ncz/2 + 1); - + Array c0(ncz / 2 + 1), c1(ncz / 2 + 1), c2(ncz / 2 + 1); + int bx = bndry->bx; // Loop over the Y dimension - for(bndry->first(); !bndry->isDone(); bndry->nextY()) { + for (bndry->first(); !bndry->isDone(); bndry->nextY()) { int x = bndry->x; int y = bndry->y; - + // Take FFT of last 3 points in domain - rfft(f(x-bx,y), ncz, c0.begin()); - rfft(f(x-2*bx,y), ncz, c1.begin()); - rfft(f(x-3*bx,y), ncz, c2.begin()); - dcomplex k0lin = (c1[0] - c0[0])/metric->dx(x-bx,y); // for kz=0 solution - + rfft(f(x - bx, y), ncz, c0.begin()); + rfft(f(x - 2 * bx, y), ncz, c1.begin()); + rfft(f(x - 3 * bx, y), ncz, c2.begin()); + dcomplex k0lin = (c1[0] - c0[0]) / metric->dx(x - bx, y); // for kz=0 solution + // Calculate Delp2 on point MXG+1 (and put into c1) - for(int jz=0;jz<=ncz/2;jz++) { - dcomplex la,lb,lc; - laplace_tridag_coefs(x-2*bx, y, jz, la, lb, lc); + for (int jz = 0; jz <= ncz / 2; jz++) { + dcomplex la, lb, lc; + laplace_tridag_coefs(x - 2 * bx, y, jz, la, lb, lc); if (bx < 0) { // Inner X - c1[jz] = la*c0[jz] + lb*c1[jz] + lc*c2[jz]; - }else { // Outer X - c1[jz] = la*c2[jz] + lb*c1[jz] + lc*c0[jz]; + c1[jz] = la * c0[jz] + lb * c1[jz] + lc * c2[jz]; + } else { // Outer X + c1[jz] = la * c2[jz] + lb * c1[jz] + lc * c0[jz]; } } // Solve metric->g11*d2f/dx2 - metric->g33*kz^2f = 0 @@ -1780,29 +2092,31 @@ void BoundaryConstLaplace::apply(Field3D &f, BoutReal UNUSED(t)) { // Loop in X towards edge of domain do { // kz = 0 solution - xpos -= metric->dx(x,y); - c2[0] = c0[0] + k0lin*xpos + 0.5*c1[0]*xpos*xpos/metric->g11(x-bx,y); + xpos -= metric->dx(x, y); + c2[0] = c0[0] + k0lin * xpos + 0.5 * c1[0] * xpos * xpos / metric->g11(x - bx, y); // kz != 0 solution - BoutReal coef = -1.0*sqrt(metric->g33(x-bx,y) / metric->g11(x-bx,y))*metric->dx(x-bx,y); - for(int jz=1;jz<=ncz/2;jz++) { - BoutReal kwave=jz*2.0*PI/metric->zlength(); // wavenumber in [rad^-1] - c0[jz] *= exp(coef*kwave); // The decaying solution only - // Add the particular solution - c2[jz] = c0[jz] - c1[jz]/(metric->g33(x-bx,y)*kwave*kwave); + BoutReal coef = -1.0 * sqrt(metric->g33(x - bx, y) / metric->g11(x - bx, y)) * + metric->dx(x - bx, y); + for (int jz = 1; jz <= ncz / 2; jz++) { + BoutReal kwave = jz * 2.0 * PI / metric->zlength(); // wavenumber in [rad^-1] + c0[jz] *= exp(coef * kwave); // The decaying solution only + // Add the particular solution + c2[jz] = c0[jz] - c1[jz] / (metric->g33(x - bx, y) * kwave * kwave); } // Reverse FFT - irfft(c2.begin(), ncz, f(x,y)); - + irfft(c2.begin(), ncz, f(x, y)); + bndry->nextX(); - x = bndry->x; y = bndry->y; - }while(!bndry->isDone()); + x = bndry->x; + y = bndry->y; + } while (!bndry->isDone()); } } /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryDivCurl::clone(BoundaryRegion *region, const list &args, - const std::map &keywords) { +BoundaryOp *BoundaryDivCurl::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { return boundaryCloneNoArguments(region, args, keywords); } @@ -1813,73 +2127,97 @@ void BoundaryDivCurl::apply(Vector2D &UNUSED(f)) { void BoundaryDivCurl::apply(Vector3D &var) { int jx, jy, jz, jzp, jzm; BoutReal tmp; - - Mesh* localmesh = var.x.getMesh(); + + Mesh *localmesh = var.x.getMesh(); Coordinates *metric = localmesh->getCoordinates(var.getLocation()); - + int ncz = localmesh->LocalNz; - + if (bndry->location != BNDRY_XOUT) { throw BoutException("ERROR: DivCurl boundary only works for outer X currently\n"); } var.toCovariant(); - + if (localmesh->xstart > 2) { - throw BoutException("Error: Div = Curl = 0 boundary condition doesn't work for MXG > 2. Sorry\n"); + throw BoutException( + "Error: Div = Curl = 0 boundary condition doesn't work for MXG > 2. Sorry\n"); } - jx = localmesh->xend+1; - for(jy=1;jyLocalNy-1;jy++) { - for(jz=0;jzxend + 1; + for (jy = 1; jy < localmesh->LocalNy - 1; jy++) { + for (jz = 0; jz < ncz; jz++) { + jzp = (jz + 1) % ncz; jzm = (jz - 1 + ncz) % ncz; // dB_y / dx = dB_x / dy - + // dB_x / dy - tmp = (var.x(jx-1,jy+1,jz) - var.x(jx-1,jy-1,jz)) / (metric->dy(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; + tmp = (var.x(jx - 1, jy + 1, jz) - var.x(jx - 1, jy - 1, jz)) / + (metric->dy(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 (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; - + // 4th order to get last point + var.y(jx + 1, jy, jz) = var.y(jx - 3, jy, jz) + 4. * metric->dx(jx, jy) * tmp; + // dB_z / dx = dB_x / dz - - 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; + + 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 (localmesh->xstart == 2) - var.z(jx+1,jy,jz) = var.z(jx-3,jy,jz) + 4.*metric->dx(jx,jy)*tmp; + var.z(jx + 1, jy, jz) = var.z(jx - 3, jy, jz) + 4. * metric->dx(jx, jy) * tmp; - // d/dx( Jmetric->g11 B_x ) = - d/dx( Jmetric->g12 B_y + Jmetric->g13 B_z) + // d/dx( Jmetric->g11 B_x ) = - d/dx( Jmetric->g12 B_y + Jmetric->g13 B_z) // - d/dy( JB^y ) - d/dz( JB^z ) - - tmp = -( metric->J(jx,jy)*metric->g12(jx,jy)*var.y(jx,jy,jz) + metric->J(jx,jy)*metric->g13(jx,jy)*var.z(jx,jy,jz) - - metric->J(jx-2,jy)*metric->g12(jx-2,jy)*var.y(jx-2,jy,jz) + metric->J(jx-2,jy)*metric->g13(jx-2,jy)*var.z(jx-2,jy,jz) ) - / (metric->dx(jx-2,jy) + metric->dx(jx-1,jy)); // First term (d/dx) using vals calculated above - tmp -= (metric->J(jx-1,jy+1)*metric->g12(jx-1,jy+1)*var.x(jx-1,jy+1,jz) - metric->J(jx-1,jy-1)*metric->g12(jx-1,jy-1)*var.x(jx-1,jy-1,jz) - + metric->J(jx-1,jy+1)*metric->g22(jx-1,jy+1)*var.y(jx-1,jy+1,jz) - metric->J(jx-1,jy-1)*metric->g22(jx-1,jy-1)*var.y(jx-1,jy-1,jz) - + metric->J(jx-1,jy+1)*metric->g23(jx-1,jy+1)*var.z(jx-1,jy+1,jz) - metric->J(jx-1,jy-1)*metric->g23(jx-1,jy-1)*var.z(jx-1,jy-1,jz)) - / (metric->dy(jx-1,jy-1) + metric->dy(jx-1,jy)); // second (d/dy) - tmp -= (metric->J(jx-1,jy)*metric->g13(jx-1,jy)*(var.x(jx-1,jy,jzp) - var.x(jx-1,jy,jzm)) + - metric->J(jx-1,jy)*metric->g23(jx-1,jy)*(var.y(jx-1,jy,jzp) - var.y(jx-1,jy,jzm)) + - metric->J(jx-1,jy)*metric->g33(jx-1,jy)*(var.z(jx-1,jy,jzp) - var.z(jx-1,jy,jzm))) / (2.*metric->dz); - - 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); + + tmp = -(metric->J(jx, jy) * metric->g12(jx, jy) * var.y(jx, jy, jz) + + metric->J(jx, jy) * metric->g13(jx, jy) * var.z(jx, jy, jz) - + metric->J(jx - 2, jy) * metric->g12(jx - 2, jy) * var.y(jx - 2, jy, jz) + + metric->J(jx - 2, jy) * metric->g13(jx - 2, jy) * var.z(jx - 2, jy, jz)) / + (metric->dx(jx - 2, jy) + + metric->dx(jx - 1, jy)); // First term (d/dx) using vals calculated above + tmp -= (metric->J(jx - 1, jy + 1) * metric->g12(jx - 1, jy + 1) * + var.x(jx - 1, jy + 1, jz) - + metric->J(jx - 1, jy - 1) * metric->g12(jx - 1, jy - 1) * + var.x(jx - 1, jy - 1, jz) + + metric->J(jx - 1, jy + 1) * metric->g22(jx - 1, jy + 1) * + var.y(jx - 1, jy + 1, jz) - + metric->J(jx - 1, jy - 1) * metric->g22(jx - 1, jy - 1) * + var.y(jx - 1, jy - 1, jz) + + metric->J(jx - 1, jy + 1) * metric->g23(jx - 1, jy + 1) * + var.z(jx - 1, jy + 1, jz) - + metric->J(jx - 1, jy - 1) * metric->g23(jx - 1, jy - 1) * + var.z(jx - 1, jy - 1, jz)) / + (metric->dy(jx - 1, jy - 1) + metric->dy(jx - 1, jy)); // second (d/dy) + tmp -= (metric->J(jx - 1, jy) * metric->g13(jx - 1, jy) * + (var.x(jx - 1, jy, jzp) - var.x(jx - 1, jy, jzm)) + + metric->J(jx - 1, jy) * metric->g23(jx - 1, jy) * + (var.y(jx - 1, jy, jzp) - var.y(jx - 1, jy, jzm)) + + metric->J(jx - 1, jy) * metric->g33(jx - 1, jy) * + (var.z(jx - 1, jy, jzp) - var.z(jx - 1, jy, jzm))) / + (2. * metric->dz); + + 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 (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); + 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); } } } /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryFree::clone(BoundaryRegion *region, const list &args, - const std::map &keywords) { +BoundaryOp *BoundaryFree::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { return boundaryCloneNoArguments(region, args, keywords); } @@ -1900,126 +2238,159 @@ void BoundaryFree::apply_ddt(Field3D &UNUSED(f)) { } /////////////////////////////////////////////////////////////// -// New free boundary implementation. Uses last grid points to extrapolate into the guard cells. -// Written by L. Easy. +// New free boundary implementation. Uses last grid points to extrapolate into the guard +// cells. +// Written by L. Easy. /////////////////////////////////////////////////////////////// // 2nd order extrapolation: -BoundaryOp* BoundaryFree_O2::clone(BoundaryRegion *region, const list &args, - const std::map &keywords) { +BoundaryOp *BoundaryFree_O2::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { return boundaryCloneNoArguments(region, args, keywords); } -inline void BoundaryFree_O2::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryFree_O2::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, + int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate2nd(f, x, bx, y, by, z); } -inline void BoundaryFree_O2::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryFree_O2::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, + int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate2nd(f, x, bx, y, by, z); } -inline void BoundaryFree_O2::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryFree_O2::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), + int x, int bx, int y, int by, int z, + BoutReal UNUSED(delta)) { extrapolate2nd(f, x, bx, y, by, z); } -inline void BoundaryFree_O2::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryFree_O2::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), + int x, int bx, int y, int by, int z, + BoutReal UNUSED(delta)) { extrapolate2nd(f, x, bx, y, by, z); } -inline void BoundaryFree_O2::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryFree_O2::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, + int z) { extrapolate2nd(f, x, bx, y, by, z); } -inline void BoundaryFree_O2::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryFree_O2::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, + int z) { extrapolate2nd(f, x, bx, y, by, z); } ////////////////////////////////// // Third order extrapolation: ////////////////////////////////// -BoundaryOp* BoundaryFree_O3::clone(BoundaryRegion *region, const list &args, - const std::map &keywords) { +BoundaryOp *BoundaryFree_O3::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { return boundaryCloneNoArguments(region, args, keywords); } -inline void BoundaryFree_O3::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryFree_O3::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, + int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate3rd(f, x, bx, y, by, z); } -inline void BoundaryFree_O3::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryFree_O3::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, + int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate3rd(f, x, bx, y, by, z); } -inline void BoundaryFree_O3::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryFree_O3::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), + int x, int bx, int y, int by, int z, + BoutReal UNUSED(delta)) { extrapolate3rd(f, x, bx, y, by, z); } -inline void BoundaryFree_O3::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryFree_O3::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), + int x, int bx, int y, int by, int z, + BoutReal UNUSED(delta)) { extrapolate3rd(f, x, bx, y, by, z); } -inline void BoundaryFree_O3::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryFree_O3::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, + int z) { extrapolate3rd(f, x, bx, y, by, z); } -inline void BoundaryFree_O3::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryFree_O3::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, + int z) { extrapolate3rd(f, x, bx, y, by, z); } // Fourth order extrapolation: -BoundaryOp* BoundaryFree_O4::clone(BoundaryRegion *region, const list &args, - const std::map &keywords) { +BoundaryOp *BoundaryFree_O4::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { return boundaryCloneNoArguments(region, args, keywords); } -inline void BoundaryFree_O4::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryFree_O4::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, + int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate4th(f, x, bx, y, by, z); } -inline void BoundaryFree_O4::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryFree_O4::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, + int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate4th(f, x, bx, y, by, z); } -inline void BoundaryFree_O4::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryFree_O4::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), + int x, int bx, int y, int by, int z, + BoutReal UNUSED(delta)) { extrapolate4th(f, x, bx, y, by, z); } -inline void BoundaryFree_O4::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryFree_O4::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), + int x, int bx, int y, int by, int z, + BoutReal UNUSED(delta)) { extrapolate4th(f, x, bx, y, by, z); } -inline void BoundaryFree_O4::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryFree_O4::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, + int z) { extrapolate4th(f, x, bx, y, by, z); } -inline void BoundaryFree_O4::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryFree_O4::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, + int z) { extrapolate4th(f, x, bx, y, by, z); } // Fifth order extrapolation: -BoundaryOp* BoundaryFree_O5::clone(BoundaryRegion *region, const list &args, - const std::map &keywords) { +BoundaryOp *BoundaryFree_O5::clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { return boundaryCloneNoArguments(region, args, keywords); } -inline void BoundaryFree_O5::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryFree_O5::applyAtPoint(Field2D &f, BoutReal UNUSED(val), int x, int bx, + int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate5th(f, x, bx, y, by, z); } -inline void BoundaryFree_O5::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryFree_O5::applyAtPoint(Field3D &f, BoutReal UNUSED(val), int x, int bx, + int y, int by, int z, BoutReal UNUSED(delta)) { extrapolate5th(f, x, bx, y, by, z); } -inline void BoundaryFree_O5::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryFree_O5::applyAtPointStaggered(Field2D &f, BoutReal UNUSED(val), + int x, int bx, int y, int by, int z, + BoutReal UNUSED(delta)) { extrapolate5th(f, x, bx, y, by, z); } -inline void BoundaryFree_O5::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), int x, int bx, int y, int by, int z, BoutReal UNUSED(delta)) { +inline void BoundaryFree_O5::applyAtPointStaggered(Field3D &f, BoutReal UNUSED(val), + int x, int bx, int y, int by, int z, + BoutReal UNUSED(delta)) { extrapolate5th(f, x, bx, y, by, z); } -inline void BoundaryFree_O5::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryFree_O5::extrapolateFurther(Field2D &f, int x, int bx, int y, int by, + int z) { extrapolate5th(f, x, bx, y, by, z); } -inline void BoundaryFree_O5::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, int z) { +inline void BoundaryFree_O5::extrapolateFurther(Field3D &f, int x, int bx, int y, int by, + int z) { extrapolate5th(f, x, bx, y, by, z); } /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryRelax::cloneMod(BoundaryOp *operation, const list &args) { - BoundaryRelax* result = new BoundaryRelax(operation, r); - +BoundaryOp *BoundaryRelax::cloneMod(BoundaryOp *operation, const list &args) { + BoundaryRelax *result = new BoundaryRelax(operation, r); + if (!args.empty()) { // First argument should be the rate BoutReal val = stringToReal(args.front()); @@ -2047,71 +2418,69 @@ void BoundaryRelax::apply_ddt(Field2D &f) { Field2D g = f; // Apply the boundary to g op->apply(g); - + bndry->first(); - + // Set time-derivatives - for(bndry->first(); !bndry->isDone(); bndry->next()) { + for (bndry->first(); !bndry->isDone(); bndry->next()) { ddt(f)(bndry->x, bndry->y) = r * (g(bndry->x, bndry->y) - f(bndry->x, bndry->y)); } } void BoundaryRelax::apply_ddt(Field3D &f) { TRACE("BoundaryRelax::apply_ddt(Field3D)"); - - Mesh* localmesh = f.getMesh(); + + 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++) { - ddt(f)(bndry->x, bndry->y, z) = r * (g(bndry->x, bndry->y, z) - f(bndry->x, bndry->y, z)); + for (bndry->first(); !bndry->isDone(); bndry->next()) + for (int z = 0; z < localmesh->LocalNz; z++) { + ddt(f)(bndry->x, bndry->y, z) = + r * (g(bndry->x, bndry->y, z) - f(bndry->x, bndry->y, z)); } } /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryToFieldAligned::cloneMod(BoundaryOp *operation, const list &args) { - BoundaryToFieldAligned* result = new BoundaryToFieldAligned(operation); - +BoundaryOp *BoundaryToFieldAligned::cloneMod(BoundaryOp *operation, + const list &args) { + BoundaryToFieldAligned *result = new BoundaryToFieldAligned(operation); + if (!args.empty()) { output << "WARNING: BoundaryToFieldAligned expected no argument\n"; - //Shouldn't we throw ? + // Shouldn't we throw ? } - + return result; } -void BoundaryToFieldAligned::apply(Field2D &f, BoutReal t) { - op->apply(f, t); -} +void BoundaryToFieldAligned::apply(Field2D &f, BoutReal t) { op->apply(f, t); } void BoundaryToFieldAligned::apply(Field3D &f, BoutReal t) { - Mesh* localmesh = f.getMesh(); + Mesh *localmesh = f.getMesh(); - //NOTE: This is not very efficient... updating entire field + // NOTE: This is not very efficient... updating entire field f = localmesh->fromFieldAligned(f); // Apply the boundary to shifted field op->apply(f, t); - //Shift back + // Shift back 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 - //have a flag to define the region in which we want to apply to/fromFieldAligned -} - -void BoundaryToFieldAligned::apply_ddt(Field2D &f) { - op->apply_ddt(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 + // have a flag to define the region in which we want to apply to/fromFieldAligned } +void BoundaryToFieldAligned::apply_ddt(Field2D &f) { op->apply_ddt(f); } + void BoundaryToFieldAligned::apply_ddt(Field3D &f) { - Mesh* localmesh = f.getMesh(); + Mesh *localmesh = f.getMesh(); f = localmesh->fromFieldAligned(f); ddt(f) = localmesh->fromFieldAligned(ddt(f)); @@ -2119,46 +2488,42 @@ void BoundaryToFieldAligned::apply_ddt(Field3D &f) { ddt(f) = localmesh->toFieldAligned(ddt(f)); } - /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryFromFieldAligned::cloneMod(BoundaryOp *operation, const list &args) { - BoundaryFromFieldAligned* result = new BoundaryFromFieldAligned(operation); - +BoundaryOp *BoundaryFromFieldAligned::cloneMod(BoundaryOp *operation, + const list &args) { + BoundaryFromFieldAligned *result = new BoundaryFromFieldAligned(operation); + if (!args.empty()) { output << "WARNING: BoundaryFromFieldAligned expected no argument\n"; - //Shouldn't we throw ? + // Shouldn't we throw ? } - + return result; } -void BoundaryFromFieldAligned::apply(Field2D &f, BoutReal t) { - op->apply(f, t); -} +void BoundaryFromFieldAligned::apply(Field2D &f, BoutReal t) { op->apply(f, t); } void BoundaryFromFieldAligned::apply(Field3D &f, BoutReal t) { - Mesh* localmesh = f.getMesh(); + Mesh *localmesh = f.getMesh(); - //NOTE: This is not very efficient... shifting entire field + // NOTE: This is not very efficient... shifting entire field f = localmesh->toFieldAligned(f); // Apply the boundary to shifted field op->apply(f, t); - //Shift back + // Shift back 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 - //have a flag to define the region in which we want to apply to/fromFieldAligned -} - -void BoundaryFromFieldAligned::apply_ddt(Field2D &f) { - op->apply_ddt(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 + // have a flag to define the region in which we want to apply to/fromFieldAligned } +void BoundaryFromFieldAligned::apply_ddt(Field2D &f) { op->apply_ddt(f); } + void BoundaryFromFieldAligned::apply_ddt(Field3D &f) { - Mesh* localmesh = f.getMesh(); + Mesh *localmesh = f.getMesh(); f = localmesh->toFieldAligned(f); ddt(f) = localmesh->toFieldAligned(ddt(f)); From 34a39b04d185b77bd1b2760d59b052620dacc971 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 12 Nov 2018 14:05:42 +0000 Subject: [PATCH 39/45] Fix implementation of 'width' in boundary conditions, use BoundaryWidth Cannot implement 'width' properly with member of BoundaryOp. Un-deprecates BoundaryWidth modifier, since this is now implemented (and needed to implement the 'width' keyword). Add 'copy' method to BoundaryRegion. Allows creating a new BoundaryRegion with a different width. Default value for 'wid' argument is -1, in which case xstart/ystart is used and the returned object is an exact copy of the original. BoundaryWidth modifier now has a member 'unique_ptr bndry' which is copied from the input BoundaryRegion, but with the width changed. --- include/boundary_op.hxx | 16 ++--- include/boundary_region.hxx | 18 +++-- include/boundary_standard.hxx | 35 +++++----- src/mesh/boundary_region.cxx | 34 ++++++--- src/mesh/boundary_standard.cxx | 124 ++++++++++++++++++++++----------- 5 files changed, 148 insertions(+), 79 deletions(-) diff --git a/include/boundary_op.hxx b/include/boundary_op.hxx index c365270f34..c6bf80a641 100644 --- a/include/boundary_op.hxx +++ b/include/boundary_op.hxx @@ -23,14 +23,11 @@ using std::list; class BoundaryOp { public: BoundaryOp(bool apply_ddt = false) - : bndry(nullptr), apply_to_ddt(apply_ddt), val(0.), gen(nullptr), width(0) {} - BoundaryOp(BoundaryRegion *region, int width_in = 0, bool apply_ddt = false) - : bndry(region), apply_to_ddt(apply_ddt), val(0.), gen(nullptr), - width(width_in ? width_in : region->width) {} - BoundaryOp(BoundaryRegion *region, BoutReal val_in, std::shared_ptr g, - int width_in = 0) - : bndry(region), apply_to_ddt(false), val(val_in), gen(std::move(g)), - width(width_in ? width_in : region->width) {} + : bndry(nullptr), apply_to_ddt(apply_ddt), val(0.), gen(nullptr) {} + BoundaryOp(BoundaryRegion *region, bool apply_ddt = false) + : bndry(region), apply_to_ddt(apply_ddt), val(0.), gen(nullptr) {} + BoundaryOp(BoundaryRegion *region, BoutReal val_in, std::shared_ptr g) + : bndry(region), apply_to_ddt(false), val(val_in), gen(std::move(g)) {} virtual ~BoundaryOp() {} // Note: All methods must implement clone, except for modifiers (see below) @@ -70,7 +67,6 @@ public: protected: const BoutReal val; // constant value for boundary condition std::shared_ptr gen; // Generator - const int width; // boundary width, stored in case we change it from the default }; /// An operation on a boundary @@ -98,7 +94,7 @@ class BoundaryModifier : public BoundaryOp { public: BoundaryModifier(bool apply_ddt = false) : BoundaryOp(apply_ddt), op(nullptr) {} BoundaryModifier(BoundaryOp *operation, bool apply_ddt = false) - : BoundaryOp(operation->bndry, 0, apply_ddt), op(operation) {} + : BoundaryOp(operation->bndry, apply_ddt), op(operation) {} virtual BoundaryOp *cloneMod(BoundaryOp *op, const list &args) = 0; virtual BoundaryOpPar *cloneMod(BoundaryOpPar *UNUSED(op), const list &UNUSED(args)) { diff --git a/include/boundary_region.hxx b/include/boundary_region.hxx index 4771671c9e..13fbacffe5 100644 --- a/include/boundary_region.hxx +++ b/include/boundary_region.hxx @@ -33,6 +33,8 @@ public: } virtual ~BoundaryRegion() {} + virtual BoundaryRegion* copy(int wid=-1) = 0; + int x,y; ///< Indices of the point in the boundary const int bx, by; ///< Direction of the boundary [x+dx][y+dy] is going outwards @@ -57,7 +59,9 @@ public: class BoundaryRegionXIn : public BoundaryRegion { public: - BoundaryRegionXIn(std::string name, int ymin, int ymax, Mesh* passmesh = nullptr); + BoundaryRegionXIn(std::string name, int ymin, int ymax, Mesh* passmesh = nullptr, int wid = -1); + + BoundaryRegion* copy(int wid = -1) override; void first() override; void next() override; @@ -72,7 +76,9 @@ private: class BoundaryRegionXOut : public BoundaryRegion { public: - BoundaryRegionXOut(std::string name, int ymin, int ymax, Mesh* passmesh = nullptr); + BoundaryRegionXOut(std::string name, int ymin, int ymax, Mesh* passmesh = nullptr, int wid = -1); + + BoundaryRegion* copy(int wid = -1) override; void first() override; void next() override; @@ -87,7 +93,9 @@ private: class BoundaryRegionYDown : public BoundaryRegion { public: - BoundaryRegionYDown(std::string name, int xmin, int xmax, Mesh* passmesh = nullptr); + BoundaryRegionYDown(std::string name, int xmin, int xmax, Mesh* passmesh = nullptr, int wid = -1); + + BoundaryRegion* copy(int wid = -1) override; void first() override; void next() override; @@ -102,7 +110,9 @@ private: class BoundaryRegionYUp : public BoundaryRegion { public: - BoundaryRegionYUp(std::string name, int xmin, int xmax, Mesh* passmesh = nullptr); + BoundaryRegionYUp(std::string name, int xmin, int xmax, Mesh* passmesh = nullptr, int wid = -1); + + BoundaryRegion* copy(int wid = -1) override; void first() override; void next() override; diff --git a/include/boundary_standard.hxx b/include/boundary_standard.hxx index 9e3d76abea..325b2fd0be 100644 --- a/include/boundary_standard.hxx +++ b/include/boundary_standard.hxx @@ -135,9 +135,9 @@ class BoundaryNeumann_NonOrthogonal : public BoundaryOp { public: BoundaryNeumann_NonOrthogonal() {} BoundaryNeumann_NonOrthogonal(BoutReal setval) - : BoundaryOp(nullptr, setval, nullptr, 0) {} + : BoundaryOp(nullptr, setval, nullptr) {} BoundaryNeumann_NonOrthogonal(BoundaryRegion *region, BoutReal setval = 0.) - : BoundaryOp(region, setval, nullptr, 0) {} + : BoundaryOp(region, setval, nullptr) {} BoundaryOp *clone(BoundaryRegion *region, const list &args, const std::map &keywords) override; @@ -477,24 +477,27 @@ private: /// Increase the width of a boundary class BoundaryWidth : public BoundaryModifier { public: - BoundaryWidth() : width(2) {} - BoundaryWidth(BoundaryOp *operation, int wid) - : BoundaryModifier(operation), width(wid) {} - BoundaryOp *cloneMod(BoundaryOp *UNUSED(op), - const list &UNUSED(args)) override { - throw BoutException("WARNING: BoundaryWidth modifier is deprecated, use 'width' " - "keyword to boundary conditions instead"); - return new BoundaryWidth(nullptr, 0); - } + BoundaryWidth() : bndry(nullptr) {} + BoundaryWidth(BoundaryOp *operation, int wid); + BoundaryOp *cloneMod(BoundaryOp *op, + const list &args) final; - void apply(Field2D &UNUSED(f), BoutReal UNUSED(t)) override{}; - void apply(Field3D &UNUSED(f), BoutReal UNUSED(t)) override{}; + void apply(Field2D &f, BoutReal t) final { + op->apply(f, t); + } + void apply(Field3D &f, BoutReal t) final { + op->apply(f, t); + } - void apply_ddt(Field2D &UNUSED(f)) override{}; - void apply_ddt(Field3D &UNUSED(f)) override{}; + void apply_ddt(Field2D &f) final { + op->apply_ddt(f); + } + void apply_ddt(Field3D &f) final { + op->apply_ddt(f); + } private: - int width; + std::unique_ptr bndry; }; /// Convert input field fromFieldAligned, apply boundary and then convert back diff --git a/src/mesh/boundary_region.cxx b/src/mesh/boundary_region.cxx index ef314751e2..ce3aa9ec9d 100644 --- a/src/mesh/boundary_region.cxx +++ b/src/mesh/boundary_region.cxx @@ -3,9 +3,10 @@ #include #include -BoundaryRegionXIn::BoundaryRegionXIn(std::string name, int ymin, int ymax, Mesh* passmesh) +BoundaryRegionXIn::BoundaryRegionXIn(std::string name, int ymin, int ymax, Mesh* passmesh, int wid) : BoundaryRegion(name, -1, 0, BNDRY_XIN, - (passmesh == nullptr ? mesh : passmesh)->xstart, passmesh), + wid < 0 ? (passmesh == nullptr ? mesh : passmesh)->xstart : wid, + passmesh), ys(ymin), ye(ymax) { x = width-1; // First point inside the boundary @@ -13,6 +14,10 @@ BoundaryRegionXIn::BoundaryRegionXIn(std::string name, int ymin, int ymax, Mesh* swap(ys, ye); } +BoundaryRegion* BoundaryRegionXIn::copy(int wid) { + return new BoundaryRegionXIn(label, ys, ye, localmesh, wid); +} + void BoundaryRegionXIn::first() { x = width-1; @@ -57,9 +62,9 @@ bool BoundaryRegionXIn::isDone() /////////////////////////////////////////////////////////////// -BoundaryRegionXOut::BoundaryRegionXOut(std::string name, int ymin, int ymax, Mesh* passmesh) +BoundaryRegionXOut::BoundaryRegionXOut(std::string name, int ymin, int ymax, Mesh* passmesh, int wid) : BoundaryRegion(name, 1, 0, BNDRY_XOUT, - (passmesh == nullptr ? mesh : passmesh)->LocalNx - (passmesh == nullptr ? mesh : passmesh)->xend - 1, + wid < 0 ? (passmesh == nullptr ? mesh : passmesh)->LocalNx - (passmesh == nullptr ? mesh : passmesh)->xend - 1 : wid, passmesh), ys(ymin), ye(ymax) { @@ -68,6 +73,10 @@ BoundaryRegionXOut::BoundaryRegionXOut(std::string name, int ymin, int ymax, Mes swap(ys, ye); } +BoundaryRegion* BoundaryRegionXOut::copy(int wid) { + return new BoundaryRegionXOut(label, ys, ye, localmesh, wid); +} + void BoundaryRegionXOut::first() { x = localmesh->LocalNx - width; @@ -112,9 +121,10 @@ bool BoundaryRegionXOut::isDone() /////////////////////////////////////////////////////////////// -BoundaryRegionYDown::BoundaryRegionYDown(std::string name, int xmin, int xmax, Mesh* passmesh) +BoundaryRegionYDown::BoundaryRegionYDown(std::string name, int xmin, int xmax, Mesh* passmesh, int wid) : BoundaryRegion(name, 0, -1, BNDRY_YDOWN, - (passmesh == nullptr ? mesh : passmesh)->ystart, passmesh), + wid < 0 ? (passmesh == nullptr ? mesh : passmesh)->ystart : wid, + passmesh), xs(xmin), xe(xmax) { y = width-1; // First point inside the boundary @@ -122,6 +132,10 @@ BoundaryRegionYDown::BoundaryRegionYDown(std::string name, int xmin, int xmax, M swap(xs, xe); } +BoundaryRegion* BoundaryRegionYDown::copy(int wid) { + return new BoundaryRegionYDown(label, xs, xe, localmesh, wid); +} + void BoundaryRegionYDown::first() { x = xs; @@ -167,9 +181,9 @@ bool BoundaryRegionYDown::isDone() /////////////////////////////////////////////////////////////// -BoundaryRegionYUp::BoundaryRegionYUp(std::string name, int xmin, int xmax, Mesh* passmesh) +BoundaryRegionYUp::BoundaryRegionYUp(std::string name, int xmin, int xmax, Mesh* passmesh, int wid) : BoundaryRegion(name, 0, 1, BNDRY_YUP, - (passmesh == nullptr ? mesh : passmesh)->LocalNy - (passmesh == nullptr ? mesh : passmesh)->yend - 1, + wid < 0 ? (passmesh == nullptr ? mesh : passmesh)->LocalNy - (passmesh == nullptr ? mesh : passmesh)->yend - 1 : wid, passmesh), xs(xmin), xe(xmax) { @@ -178,6 +192,10 @@ BoundaryRegionYUp::BoundaryRegionYUp(std::string name, int xmin, int xmax, Mesh* swap(xs, xe); } +BoundaryRegion* BoundaryRegionYUp::copy(int wid) { + return new BoundaryRegionYUp(label, xs, xe, localmesh, wid); +} + void BoundaryRegionYUp::first() { x = xs; diff --git a/src/mesh/boundary_standard.cxx b/src/mesh/boundary_standard.cxx index 03e22f3f0a..1282a4df4e 100644 --- a/src/mesh/boundary_standard.cxx +++ b/src/mesh/boundary_standard.cxx @@ -147,16 +147,24 @@ BoundaryOp *boundaryClone(BoundaryRegion *region, const list &args, newgen = FieldFactory::get()->parse(expr); } } - int width = region->width; for (const auto &it : keywords) { if (it.first == "width") { - width = stringToInt(it.second); + int width = stringToInt(it.second); + + // remove this keyword from keywords that we pass through + auto new_keywords = keywords; + new_keywords.erase("width"); + + // Need to use BoundaryWidth modifier to implement this keyword. + // Clone a version of this boundary condition without 'width' and pass + // to a BoundaryWidth modifier. + return new BoundaryWidth(boundaryClone(region, args, new_keywords), width); } else { throw BoutException("Unrecognized boundary condition keyword %s for %s boundary", it.first.c_str(), region->label.c_str()); } } - return new T(region, val, newgen, width); + return new T(region, val, newgen); } template @@ -168,16 +176,24 @@ BoundaryOp *boundaryCloneNoArguments(BoundaryRegion *region, const list output << "WARNING: Ignoring arguments to BoundaryOp for " << region->label << " region\n"; } - int width = region->width; for (const auto &it : keywords) { if (it.first == "width") { - width = stringToInt(it.second); + int width = stringToInt(it.second); + + // remove this keyword from keywords that we pass through + auto new_keywords = keywords; + new_keywords.erase("width"); + + // Need to use BoundaryWidth modifier to implement this keyword. + // Clone a version of this boundary condition without 'width' and pass + // to a BoundaryWidth modifier. + return new BoundaryWidth(boundaryClone(region, args, new_keywords), width); } else { throw BoutException("Unrecognized boundary condition keyword %s for %s boundary", it.first.c_str(), region->label.c_str()); } } - return new T(region, width); + return new T(region); } } @@ -241,7 +257,7 @@ void BoundaryOpWithApply::applyTemplate(T &f, BoutReal t) // Need to set second guard cell, as may be used for interpolation or upwinding // derivatives - for (int i = 1; i < width; i++) { + for (int i = 1; i < bndry->width; i++) { int x = bndry->x + i * bndry->bx; int y = bndry->y + i * bndry->by; for (int z = 0; z < nz; z++) { @@ -275,7 +291,7 @@ void BoundaryOpWithApply::applyTemplate(T &f, BoutReal t) // Need to set second guard cell, as may be used for interpolation or // upwinding derivatives - for (int i = 1; i < width; i++) { + for (int i = 1; i < bndry->width; i++) { int x = bndry->x + i * bndry->bx; Derived::extrapolateFurther(f, x, bndry->bx, bndry->y, 0, z); } @@ -307,7 +323,7 @@ void BoundaryOpWithApply::applyTemplate(T &f, BoutReal t) // Need to set second and third guard cells, as may be used for interpolation // or upwinding derivatives - for (int i = 0; i < width; i++) { + for (int i = 0; i < bndry->width; i++) { int x = bndry->x + i * bndry->bx; Derived::extrapolateFurther(f, x, bndry->bx, bndry->y, 0, z); } @@ -340,7 +356,7 @@ void BoundaryOpWithApply::applyTemplate(T &f, BoutReal t) // Need to set second guard cell, as may be used for interpolation or // upwinding derivatives - for (int i = 1; i < width; i++) { + for (int i = 1; i < bndry->width; i++) { int y = bndry->y + i * bndry->by; Derived::extrapolateFurther(f, bndry->x, 0, y, bndry->by, z); } @@ -374,7 +390,7 @@ void BoundaryOpWithApply::applyTemplate(T &f, BoutReal t) // Need to set second guard cell, as may be used for interpolation or // upwinding derivatives - for (int i = 1; i < width; i++) { + for (int i = 1; i < bndry->width; i++) { int y = bndry->y + i * bndry->by; Derived::extrapolateFurther(f, bndry->x, 0, y, bndry->by, z); } @@ -405,7 +421,7 @@ void BoundaryOpWithApply::applyTemplate(T &f, BoutReal t) // Need to set second guard cell, as may be used for interpolation or // upwinding derivatives - for (int i = 0; i < width; i++) { + for (int i = 0; i < bndry->width; i++) { int y = bndry->y + i * bndry->by; Derived::extrapolateFurther(f, bndry->x, 0, y, bndry->by, z); } @@ -438,7 +454,7 @@ void BoundaryOpWithApply::applyTemplate(T &f, BoutReal t) // Need to set second guard cell, as may be used for interpolation or // upwinding derivatives - for (int i = 1; i < width; i++) { + for (int i = 1; i < bndry->width; i++) { int x = bndry->x + i * bndry->bx; Derived::extrapolateFurther(f, x, bndry->bx, bndry->y, 0, z); } @@ -479,7 +495,7 @@ void BoundaryOpWithApply::applyTemplate(T &f, BoutReal t) // Need to set second guard cell, as may be used for interpolation or upwinding // derivatives - for (int i = 1; i < width; i++) { + for (int i = 1; i < bndry->width; i++) { int x = bndry->x + i * bndry->bx; int y = bndry->y + i * bndry->by; Derived::extrapolateFurther(f, x, bndry->bx, y, bndry->by, z); @@ -506,7 +522,7 @@ void BoundaryOpWithApply::applyTemplate(T &f, BoutReal t) // Need to set second guard cell, as may be used for interpolation or upwinding // derivatives - for (int i = 1; i < width; i++) { + for (int i = 1; i < bndry->width; i++) { int x = bndry->x + i * bndry->bx; int y = bndry->y + i * bndry->by; for (int z = 0; z < nz; z++) { @@ -533,7 +549,7 @@ void BoundaryOpWithApply::applyTemplate(T &f, BoutReal t) // Need to set second guard cell, as may be used for interpolation or // upwinding derivatives - for (int i = 1; i < width; i++) { + for (int i = 1; i < bndry->width; i++) { int x = bndry->x + i * bndry->bx; Derived::extrapolateFurther(f, x, bndry->bx, bndry->y, 0, z); } @@ -557,7 +573,7 @@ void BoundaryOpWithApply::applyTemplate(T &f, BoutReal t) // Need to set second and third guard cells, as may be used for interpolation // or upwinding derivatives - for (int i = 0; i < width; i++) { + for (int i = 0; i < bndry->width; i++) { int x = bndry->x + i * bndry->bx; Derived::extrapolateFurther(f, x, bndry->bx, bndry->y, 0, z); } @@ -579,7 +595,7 @@ void BoundaryOpWithApply::applyTemplate(T &f, BoutReal t) // Need to set second guard cell, as may be used for interpolation or // upwinding derivatives - for (int i = 1; i < width; i++) { + for (int i = 1; i < bndry->width; i++) { int y = bndry->y + i * bndry->by; Derived::extrapolateFurther(f, bndry->x, 0, y, bndry->by, z); } @@ -606,7 +622,7 @@ void BoundaryOpWithApply::applyTemplate(T &f, BoutReal t) // Need to set second guard cell, as may be used for interpolation or // upwinding derivatives - for (int i = 1; i < width; i++) { + for (int i = 1; i < bndry->width; i++) { int y = bndry->y + i * bndry->by; Derived::extrapolateFurther(f, bndry->x, 0, y, bndry->by, z); } @@ -629,7 +645,7 @@ void BoundaryOpWithApply::applyTemplate(T &f, BoutReal t) // Need to set second guard cell, as may be used for interpolation or // upwinding derivatives - for (int i = 0; i < width; i++) { + for (int i = 0; i < bndry->width; i++) { int y = bndry->y + i * bndry->by; Derived::extrapolateFurther(f, bndry->x, 0, y, bndry->by, z); } @@ -651,7 +667,7 @@ void BoundaryOpWithApply::applyTemplate(T &f, BoutReal t) // Need to set second guard cell, as may be used for interpolation or // upwinding derivatives - for (int i = 1; i < width; i++) { + for (int i = 1; i < bndry->width; i++) { int x = bndry->x + i * bndry->bx; Derived::extrapolateFurther(f, x, bndry->bx, bndry->y, 0, z); } @@ -675,7 +691,7 @@ void BoundaryOpWithApply::applyTemplate(T &f, BoutReal t) // Need to set second guard cell, as may be used for interpolation or upwinding // derivatives - for (int i = 1; i < width; i++) { + for (int i = 1; i < bndry->width; i++) { int x = bndry->x + i * bndry->bx; int y = bndry->y + i * bndry->by; Derived::extrapolateFurther(f, x, bndry->bx, y, bndry->by, z); @@ -774,7 +790,7 @@ template void BoundaryDirichlet::applyTemplate(T &f, BoutReal t) { // This loop is our alternative approach to setting the rest of the boundary // points. Instead of extrapolating we just use the generated values. This // can help with the stability of higher order methods. - for (int i = 1; i < width; i++) { + for (int i = 1; i < bndry->width; i++) { // 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; @@ -805,7 +821,7 @@ template void BoundaryDirichlet::applyTemplate(T &f, BoutReal t) { // Need to set second guard cell, as may be used for interpolation or // upwinding derivatives - for (int i = 1; i < width; i++) { + for (int i = 1; i < bndry->width; i++) { int xi = bndry->x + i * bndry->bx; int yi = bndry->y; @@ -829,7 +845,7 @@ template void BoundaryDirichlet::applyTemplate(T &f, BoutReal t) { // Need to set second guard cell, as may be used for interpolation or // upwinding derivatives - for (int i = 0; i < width; i++) { + for (int i = 0; i < bndry->width; i++) { int xi = bndry->x + i * bndry->bx; int yi = bndry->y; @@ -857,7 +873,7 @@ template void BoundaryDirichlet::applyTemplate(T &f, BoutReal t) { // Need to set second guard cell, as may be used for interpolation or // upwinding derivatives - for (int i = 1; i < width; i++) { + for (int i = 1; i < bndry->width; i++) { int xi = bndry->x; int yi = bndry->y + i * bndry->by; @@ -884,7 +900,7 @@ template void BoundaryDirichlet::applyTemplate(T &f, BoutReal t) { // Need to set second guard cell, as may be used for interpolation or // upwinding derivatives - for (int i = 1; i < width; i++) { + for (int i = 1; i < bndry->width; i++) { int xi = bndry->x; int yi = bndry->y + i * bndry->by; @@ -908,7 +924,7 @@ template void BoundaryDirichlet::applyTemplate(T &f, BoutReal t) { // Need to set second guard cell, as may be used for interpolation or // upwinding derivatives - for (int i = 0; i < width; i++) { + for (int i = 0; i < bndry->width; i++) { int xi = bndry->x; int yi = bndry->y + i * bndry->by; @@ -936,7 +952,7 @@ template void BoundaryDirichlet::applyTemplate(T &f, BoutReal t) { // Need to set second guard cell, as may be used for interpolation or // upwinding derivatives - for (int i = 1; i < width; i++) { + for (int i = 1; i < bndry->width; i++) { int xi = bndry->x + i * bndry->bx; int yi = bndry->y; @@ -973,7 +989,7 @@ template void BoundaryDirichlet::applyTemplate(T &f, BoutReal t) { // Need to set second guard cell, as may be used for interpolation or upwinding // derivatives - for (int i = 1; i < width; i++) { + for (int i = 1; i < bndry->width; i++) { int xi = bndry->x + i * bndry->bx; int yi = bndry->y; @@ -1024,7 +1040,7 @@ template void BoundaryDirichlet::applyTemplate(T &f, BoutReal t) { // This loop is our alternative approach to setting the rest of the boundary // points. Instead of extrapolating we just use the generated values. This // can help with the stability of higher order methods. - for (int i = 1; i < width; i++) { + for (int i = 1; i < bndry->width; i++) { // 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; @@ -1043,7 +1059,7 @@ template void BoundaryDirichlet::applyTemplate(T &f, BoutReal t) { // Need to set second guard cell, as may be used for interpolation or // upwinding derivatives - for (int i = 1; i < width; i++) { + for (int i = 1; i < bndry->width; i++) { int xi = bndry->x + i * bndry->bx; int yi = bndry->y; @@ -1060,7 +1076,7 @@ template void BoundaryDirichlet::applyTemplate(T &f, BoutReal t) { // Need to set second guard cell, as may be used for interpolation or // upwinding derivatives - for (int i = 0; i < width; i++) { + for (int i = 0; i < bndry->width; i++) { int xi = bndry->x + i * bndry->bx; int yi = bndry->y; @@ -1078,7 +1094,7 @@ template void BoundaryDirichlet::applyTemplate(T &f, BoutReal t) { // Need to set second guard cell, as may be used for interpolation or // upwinding derivatives - for (int i = 1; i < width; i++) { + for (int i = 1; i < bndry->width; i++) { int xi = bndry->x; int yi = bndry->y + i * bndry->by; @@ -1098,7 +1114,7 @@ template void BoundaryDirichlet::applyTemplate(T &f, BoutReal t) { // Need to set second guard cell, as may be used for interpolation or // upwinding derivatives - for (int i = 1; i < width; i++) { + for (int i = 1; i < bndry->width; i++) { int xi = bndry->x; int yi = bndry->y + i * bndry->by; @@ -1115,7 +1131,7 @@ template void BoundaryDirichlet::applyTemplate(T &f, BoutReal t) { // Need to set second guard cell, as may be used for interpolation or // upwinding derivatives - for (int i = 0; i < width; i++) { + for (int i = 0; i < bndry->width; i++) { int xi = bndry->x; int yi = bndry->y + i * bndry->by; @@ -1133,7 +1149,7 @@ template void BoundaryDirichlet::applyTemplate(T &f, BoutReal t) { // Need to set second guard cell, as may be used for interpolation or // upwinding derivatives - for (int i = 1; i < width; i++) { + for (int i = 1; i < bndry->width; i++) { int xi = bndry->x + i * bndry->bx; int yi = bndry->y; @@ -1152,7 +1168,7 @@ template void BoundaryDirichlet::applyTemplate(T &f, BoutReal t) { // Need to set second guard cell, as may be used for interpolation or upwinding // derivatives - for (int i = 1; i < width; i++) { + for (int i = 1; i < bndry->width; i++) { int xi = bndry->x + i * bndry->bx; int yi = bndry->y; @@ -1448,7 +1464,7 @@ void BoundaryNeumann_NonOrthogonal::applyTemplate(T &f, BoutReal UNUSED(t)) { BoutReal delta = bndry->bx * metric->dx(bndry->x, bndry->y); f(bndry->x, bndry->y, z) = f(bndry->x - bndry->bx, bndry->y, z) + delta / g11shift * (val - xshift); - if (width == 2) { + if (bndry->width == 2) { f(bndry->x + bndry->bx, bndry->y, z) = f(bndry->x - 2 * bndry->bx, bndry->y, z) + 3.0 * delta / g11shift * (val - xshift); @@ -1458,14 +1474,14 @@ void BoundaryNeumann_NonOrthogonal::applyTemplate(T &f, BoutReal UNUSED(t)) { // no need to shift this b/c we want parallel nuemann not theta BoutReal delta = bndry->by * metric->dy(bndry->x, bndry->y); f(bndry->x, bndry->y, z) = f(bndry->x, bndry->y - bndry->by, z) + delta * val; - if (width == 2) { + if (bndry->width == 2) { f(bndry->x, bndry->y + bndry->by, z) = f(bndry->x, bndry->y - 2 * bndry->by, z) + 3.0 * delta * val; } } else { // set corners to zero f(bndry->x, bndry->y, z) = 0.0; - if (width == 2) { + if (bndry->width == 2) { f(bndry->x + bndry->bx, bndry->y + bndry->by, z) = 0.0; } } @@ -2446,6 +2462,32 @@ void BoundaryRelax::apply_ddt(Field3D &f) { /////////////////////////////////////////////////////////////// +BoundaryWidth::BoundaryWidth(BoundaryOp *operation, int width) + : BoundaryModifier(operation) { + + // create a new BoundaryRegion, copied from the input one but with a + // different width + bndry = std::unique_ptr(op->bndry->copy(width)); + + // set BoundaryOp op to use the new bndry + op->bndry = bndry.get(); +} + +BoundaryOp* BoundaryWidth::cloneMod(BoundaryOp *operation, + const list &args) { + int width = -1; + if(args.empty()) { + output << "WARNING: BoundaryWidth expected 1 argument\n"; + }else { + // First argument should be the rate + width = stringToInt(args.front()); + } + + return new BoundaryWidth(operation, width); +} + +/////////////////////////////////////////////////////////////// + BoundaryOp *BoundaryToFieldAligned::cloneMod(BoundaryOp *operation, const list &args) { BoundaryToFieldAligned *result = new BoundaryToFieldAligned(operation); From 1f588a45fc0c432acf3735e484494d4268030075 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 12 Nov 2018 16:21:19 +0000 Subject: [PATCH 40/45] Clear existing boundaries in FieldData::setBoundary() Otherwise if setBoundary() is called twice, the first set of boundary conditions will be applied and then the values overwritten by the second set. This is inefficient, and might cause unexpected behaviour, e.g. if the second set of boundary conditions specified "none" for some boundaries where the first set did not. --- src/field/field2d.cxx | 2 +- src/field/field3d.cxx | 2 +- src/field/field_data.cxx | 13 +++++++++++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index a2ad23dd58..e374f14484 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -349,7 +349,7 @@ void Field2D::applyTDerivBoundary() { } void Field2D::setBoundaryTo(const Field2D &f2d) { - TRACE("Field2D::setBoundary(const Field2D&)"); + TRACE("Field2D::setBoundaryTo(const Field2D&)"); checkData(f2d); diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 125dc2454d..189f59a892 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -506,7 +506,7 @@ void Field3D::applyTDerivBoundary() { } void Field3D::setBoundaryTo(const Field3D &f3d) { - TRACE("Field3D::setBoundary(const Field3D&)"); + TRACE("Field3D::setBoundaryTo(const Field3D&)"); checkData(f3d); diff --git a/src/field/field_data.cxx b/src/field/field_data.cxx index 982626a362..84c04809ac 100644 --- a/src/field/field_data.cxx +++ b/src/field/field_data.cxx @@ -19,6 +19,13 @@ void FieldData::setBoundary(const string &name) { BoundaryFactory *bfact = BoundaryFactory::getInstance(); output_info << "Setting boundary for variable " << name << endl; + + /// Get rid of existing boundary ops + for (auto &op : bndry_op) { + delete op; + } + bndry_op.clear(); + /// Loop over the mesh boundary regions for(const auto& reg : getDataMesh()->getBoundaries()) { BoundaryOp* op = bfact->createFromOptions(name, reg); @@ -27,6 +34,12 @@ void FieldData::setBoundary(const string &name) { output_info << endl; } + /// Get rid of existing parallel boundary ops + for (auto &op : bndry_op_par) { + delete op; + } + bndry_op_par.clear(); + /// Get the mesh boundary regions vector par_reg = getDataMesh()->getBoundariesPar(); /// Loop over the mesh parallel boundary regions From 2e17480ff19327d0ae52c3f34452904e2b8f4727 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 12 Nov 2018 15:47:04 +0000 Subject: [PATCH 41/45] Store BoundaryRegion's and BoundarRegionPar's in unique_ptr's In Mesh/BoutMesh keep boundary objects in a vector< std::unique_ptr > and vector< std::unique_ptr > instead of vector and vector. --- include/bout/mesh.hxx | 12 ++++++++---- src/field/field2d.cxx | 4 ++-- src/field/field3d.cxx | 12 ++++++------ src/field/field_data.cxx | 9 ++++----- src/mesh/coordinates.cxx | 2 +- src/mesh/impls/bout/boutmesh.cxx | 26 ++++++++++---------------- src/mesh/impls/bout/boutmesh.hxx | 8 ++++---- 7 files changed, 35 insertions(+), 38 deletions(-) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 080159e349..9a0978a4a0 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -387,16 +387,20 @@ class Mesh { // Boundary regions /// Return a vector containing all the boundary regions on this processor - virtual vector getBoundaries() = 0; + virtual vector< std::unique_ptr >& getBoundaries() = 0; /// Add a boundary region to this processor - virtual void addBoundary(BoundaryRegion* UNUSED(bndry)) {} + virtual void addBoundary(BoundaryRegion* UNUSED(bndry)) { + throw BoutException("Mesh::addBoundary() is not implemented"); + } /// Get all the parallel (Y) boundaries on this processor - virtual vector getBoundariesPar() = 0; + virtual vector< std::unique_ptr >& getBoundariesPar() = 0; /// Add a parallel(Y) boundary to this processor - virtual void addBoundaryPar(BoundaryRegionPar* UNUSED(bndry)) {} + virtual void addBoundaryPar(BoundaryRegionPar* UNUSED(bndry)) { + throw BoutException("Mesh::addBoundaryRegionPar() is not implemented"); + } /// Branch-cut special handling (experimental) virtual const Field3D smoothSeparatrix(const Field3D &f) {return f;} diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index e374f14484..d2531e6164 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -271,7 +271,7 @@ void Field2D::applyBoundary(const string &condition) { /// Loop over the mesh boundary regions for(const auto& reg : fieldmesh->getBoundaries()) { - BoundaryOp* op = static_cast(bfact->create(condition, reg)); + BoundaryOp* op = static_cast(bfact->create(condition, reg.get())); op->apply(*this); delete op; } @@ -307,7 +307,7 @@ void Field2D::applyBoundary(const string ®ion, const string &condition) { for (const auto ® : fieldmesh->getBoundaries()) { if (reg->label.compare(region) == 0) { region_found = true; - BoundaryOp *op = static_cast(bfact->create(condition, reg)); + BoundaryOp *op = static_cast(bfact->create(condition, reg.get())); op->apply(*this); delete op; break; diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 189f59a892..72cccf05f6 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -454,7 +454,7 @@ void Field3D::applyBoundary(const string &condition) { /// Loop over the mesh boundary regions for(const auto& reg : fieldmesh->getBoundaries()) { - BoundaryOp* op = bfact->create(condition, reg); + BoundaryOp* op = bfact->create(condition, reg.get()); op->apply(*this); delete op; } @@ -474,7 +474,7 @@ void Field3D::applyBoundary(const string ®ion, const string &condition) { for (const auto ® : fieldmesh->getBoundaries()) { if (reg->label.compare(region) == 0) { region_found = true; - BoundaryOp *op = bfact->create(condition, reg); + BoundaryOp *op = bfact->create(condition, reg.get()); op->apply(*this); delete op; break; @@ -581,7 +581,7 @@ void Field3D::applyParallelBoundary(const string &condition) { /// Loop over the mesh boundary regions for(const auto& reg : fieldmesh->getBoundariesPar()) { - BoundaryOpPar* op = bfact->create(condition, reg); + BoundaryOpPar* op = bfact->create(condition, reg.get()); op->apply(*this); delete op; } @@ -606,7 +606,7 @@ void Field3D::applyParallelBoundary(const string ®ion, const string &conditio /// Loop over the mesh boundary regions for(const auto& reg : fieldmesh->getBoundariesPar()) { if(reg->label.compare(region) == 0) { - BoundaryOpPar* op = bfact->create(condition, reg); + BoundaryOpPar* op = bfact->create(condition, reg.get()); op->apply(*this); delete op; break; @@ -635,9 +635,9 @@ void Field3D::applyParallelBoundary(const string ®ion, const string &conditio if(reg->label.compare(region) == 0) { // BoundaryFactory can't create boundaries using Field3Ds, so get temporary // boundary of the right type - BoundaryOpPar* tmp = bfact->create(condition, reg); + BoundaryOpPar* tmp = bfact->create(condition, reg.get()); // then clone that with the actual argument - BoundaryOpPar* op = tmp->clone(reg, f); + BoundaryOpPar* op = tmp->clone(reg.get(), f); op->apply(*this); delete tmp; delete op; diff --git a/src/field/field_data.cxx b/src/field/field_data.cxx index 84c04809ac..7503f95df1 100644 --- a/src/field/field_data.cxx +++ b/src/field/field_data.cxx @@ -28,7 +28,7 @@ void FieldData::setBoundary(const string &name) { /// Loop over the mesh boundary regions for(const auto& reg : getDataMesh()->getBoundaries()) { - BoundaryOp* op = bfact->createFromOptions(name, reg); + BoundaryOp* op = bfact->createFromOptions(name, reg.get()); if (op != nullptr) bndry_op.push_back(op); output_info << endl; @@ -40,11 +40,9 @@ void FieldData::setBoundary(const string &name) { } bndry_op_par.clear(); - /// Get the mesh boundary regions - vector par_reg = getDataMesh()->getBoundariesPar(); /// Loop over the mesh parallel boundary regions for(const auto& reg : getDataMesh()->getBoundariesPar()) { - BoundaryOpPar* op = bfact->createFromOptions(name, reg); + BoundaryOpPar* op = bfact->createFromOptions(name, reg.get()); if (op != nullptr) bndry_op_par.push_back(op); output_info << endl; @@ -55,8 +53,9 @@ void FieldData::setBoundary(const string &name) { } void FieldData::setBoundary(const string &UNUSED(region), BoundaryOp *op) { + throw BoutException("FieldData::setBoundary(region, op) is not implemented"); /// Get the mesh boundary regions - vector reg = getDataMesh()->getBoundaries(); + auto& reg = getDataMesh()->getBoundaries(); /// Find the region diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 81c0e921e4..368bac7836 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -187,7 +187,7 @@ namespace { // Note: cannot use applyBoundary("neumann") here because applyBoundary() // would try to create a new Coordinates object since we have not finished // initializing yet, leading to an infinite recursion - for (auto bndry : localmesh->getBoundaries()) { + for (auto &bndry : localmesh->getBoundaries()) { if (bndry->bx != 0) { // If bx!=0 we are on an x-boundary, inner if bx>0 and outer if bx<0 for(bndry->first(); !bndry->isDone(); bndry->next1d()) { diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index 85f2233f80..fc0b00cb21 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -71,12 +71,6 @@ BoutMesh::~BoutMesh() { // Delete the communication handles clear_handles(); - // Delete the boundary regions - for (const auto &bndry : boundary) - delete bndry; - for (const auto &bndry : par_boundary) - delete bndry; - if (comm_x != MPI_COMM_NULL) MPI_Comm_free(&comm_x); if (comm_inner != MPI_COMM_NULL) @@ -796,15 +790,15 @@ int BoutMesh::load() { if (((yg > jyseps1_1) && (yg <= jyseps2_1)) || ((yg > jyseps1_2) && (yg <= jyseps2_2))) { // Core - boundary.push_back(new BoundaryRegionXIn("core", ystart, yend, this)); + boundary.push_back(std::unique_ptr(new BoundaryRegionXIn("core", ystart, yend, this))); } else { // PF region - boundary.push_back(new BoundaryRegionXIn("pf", ystart, yend, this)); + boundary.push_back(std::unique_ptr(new BoundaryRegionXIn("pf", ystart, yend, this))); } } if (PE_XIND == (NXPE - 1)) { // Outer SOL - boundary.push_back(new BoundaryRegionXOut("sol", ystart, yend, this)); + boundary.push_back(std::unique_ptr(new BoundaryRegionXOut("sol", ystart, yend, this))); } } @@ -812,15 +806,15 @@ int BoutMesh::load() { // Need boundaries in Y if ((UDATA_INDEST < 0) && (UDATA_XSPLIT > xstart)) - boundary.push_back(new BoundaryRegionYUp("upper_target", xstart, UDATA_XSPLIT - 1, this)); + boundary.push_back(std::unique_ptr(new BoundaryRegionYUp("upper_target", xstart, UDATA_XSPLIT - 1, this))); if ((UDATA_OUTDEST < 0) && (UDATA_XSPLIT <= xend)) - boundary.push_back(new BoundaryRegionYUp("upper_target", UDATA_XSPLIT, xend, this)); + boundary.push_back(std::unique_ptr(new BoundaryRegionYUp("upper_target", UDATA_XSPLIT, xend, this))); if ((DDATA_INDEST < 0) && (DDATA_XSPLIT > xstart)) boundary.push_back( - new BoundaryRegionYDown("lower_target", xstart, DDATA_XSPLIT - 1, this)); + std::unique_ptr(new BoundaryRegionYDown("lower_target", xstart, DDATA_XSPLIT - 1, this))); if ((DDATA_OUTDEST < 0) && (DDATA_XSPLIT <= xend)) - boundary.push_back(new BoundaryRegionYDown("lower_target", DDATA_XSPLIT, xend, this)); + boundary.push_back(std::unique_ptr(new BoundaryRegionYDown("lower_target", DDATA_XSPLIT, xend, this))); } if (!boundary.empty()) { @@ -2379,13 +2373,13 @@ const RangeIterator BoutMesh::iterateBndryUpperY() const { return RangeIterator(xs, xe); } -vector BoutMesh::getBoundaries() { return boundary; } +vector< std::unique_ptr >& BoutMesh::getBoundaries() { return boundary; } -vector BoutMesh::getBoundariesPar() { return par_boundary; } +vector< std::unique_ptr >& BoutMesh::getBoundariesPar() { return par_boundary; } void BoutMesh::addBoundaryPar(BoundaryRegionPar *bndry) { output_info << "Adding new parallel boundary: " << bndry->label << endl; - par_boundary.push_back(bndry); + par_boundary.push_back(std::unique_ptr(bndry)); } const Field3D BoutMesh::smoothSeparatrix(const Field3D &f) { diff --git a/src/mesh/impls/bout/boutmesh.hxx b/src/mesh/impls/bout/boutmesh.hxx index 91d6c25036..8fa0f1d8a1 100644 --- a/src/mesh/impls/bout/boutmesh.hxx +++ b/src/mesh/impls/bout/boutmesh.hxx @@ -138,8 +138,8 @@ class BoutMesh : public Mesh { // Boundary regions - vector getBoundaries(); - vector getBoundariesPar(); + vector< std::unique_ptr >& getBoundaries(); + vector< std::unique_ptr >& getBoundariesPar(); void addBoundaryPar(BoundaryRegionPar* bndry); const Field3D smoothSeparatrix(const Field3D &f); @@ -221,8 +221,8 @@ class BoutMesh : public Mesh { void addBoundaryRegions(); ///< Adds 2D and 3D regions for boundaries - vector boundary; // Vector of boundary regions - vector par_boundary; // Vector of parallel boundary regions + vector< std::unique_ptr > boundary; // Vector of boundary regions + vector< std::unique_ptr > par_boundary; // Vector of parallel boundary regions ////////////////////////////////////////////////// // Communications From ee22ccf6b925239e5f9bf238edf4706060bd1e0e Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 12 Nov 2018 16:23:07 +0000 Subject: [PATCH 42/45] Implement FieldData::setBoundary(region, op) This previously did nothing, although it is not used anywhere. --- src/field/field_data.cxx | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/field/field_data.cxx b/src/field/field_data.cxx index 7503f95df1..c5a5117ad1 100644 --- a/src/field/field_data.cxx +++ b/src/field/field_data.cxx @@ -52,21 +52,38 @@ void FieldData::setBoundary(const string &name) { boundaryIsCopy = false; } -void FieldData::setBoundary(const string &UNUSED(region), BoundaryOp *op) { - throw BoutException("FieldData::setBoundary(region, op) is not implemented"); - /// Get the mesh boundary regions - auto& reg = getDataMesh()->getBoundaries(); - - /// Find the region +void FieldData::setBoundary(const string ®ion, BoundaryOp *op) { + output_info << "Setting " << region << " boundary for some variable" << endl; + + /// Find the region + BoundaryRegion* region_ptr = nullptr; + for (const auto& bndry : getDataMesh()->getBoundaries()) { + if (bndry->label == region) { + region_ptr = bndry.get(); + } + } /// Find if we're replacing an existing boundary - for(const auto& bndry : bndry_op) { - if( bndry->bndry == op->bndry ) { + for(auto it = bndry_op.begin(); it != bndry_op.end(); it++) { + if( (*it)->bndry == region_ptr ) { // Replacing this boundary - output << "Replacing "; + + output << "Replacing " << region_ptr->label<clone(region_ptr, {}, {}); + + bndry_op.push_back(new_op); } void FieldData::copyBoundary(const FieldData &f) { From 9a4b72aead382d0a7233bbdc0312198b1a778129 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 12 Nov 2018 16:42:44 +0000 Subject: [PATCH 43/45] Update manual entry on boundary conditions --- include/boundary_factory.hxx | 4 +++ manual/sphinx/user_docs/boundary_options.rst | 28 ++++++++++++-------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/include/boundary_factory.hxx b/include/boundary_factory.hxx index e6713f7c83..11cd1a8283 100644 --- a/include/boundary_factory.hxx +++ b/include/boundary_factory.hxx @@ -24,6 +24,10 @@ using BoundaryRegionOp = typename std::conditional)`` - Set to some number e.g. ``dirichlet(1)`` sets the boundary to :math:`1.0` -- ``neumann`` - Zero gradient +- ``neumann()`` - Set gradient to some number (default zero). Gradient + is in internal coordinates, i.e. using dx/dy for grid spacing with no metric + terms. - ``robin`` - A combination of zero-gradient and zero-value :math:`a f + b{{\frac{\partial f}{\partial x}}} = g` where the @@ -54,6 +56,11 @@ brackets. Currently implemented boundary conditions are: - ``constlaplace`` - Laplacian = const, decaying solution (X boundaries only) +Keyword arguments can also be given. Currently only ``width`` is implemented, +which reproduces the functionality of the ``width`` boundary modifier described +below. For example, ``dirichlet(3., width=4)`` is equivalent to +``width(dirichlet(3.), 4)``. + The zero- or constant-Laplacian boundary conditions works as follows: .. math:: @@ -75,9 +82,10 @@ which has the solution Assuming that the solution should decay away from the domain, on the inner :math:`x` boundary :math:`B = 0`, and on the outer boundary -:math:`A = 0`. Boundary modifiers change the behaviour of boundary -conditions, and more than one modifier can be used. Currently the -following are available: +:math:`A = 0`. + +Boundary modifiers change the behaviour of boundary conditions, and more than +one modifier can be used. Currently the following are available: - ``relax`` - Relaxing boundaries. Evolve the variable towards the given boundary condition at a given rate @@ -137,10 +145,11 @@ the core boundary. Changing the width of boundaries -------------------------------- -To change the width of a boundary region, the ``width`` modifier changes -the width of a boundary region before applying the boundary condition, -then changes the width back afterwards. To use, specify the boundary -condition and the width, for example +To change the width of a boundary region, the ``width`` modifier creates a copy +of the BoundaryRegion object with a different ``width`` parameter. This copy is +stored in the BoundaryWidth object, and a pointer to the BoundaryRegion passed +to the BoundaryOp. To use, specify the boundary condition and the width, for +example :: @@ -165,9 +174,6 @@ width. Limitations: -#. Because it modifies then restores a globally-used BoundaryRegion, - this code is not thread safe. - #. Boundary conditions can’t be applied across processors, and no checks are done that the width asked for fits within a single processor. From 94d4e0dab4850ce647ad62b1cda54cac9e3c3f50 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 12 Nov 2018 16:50:26 +0000 Subject: [PATCH 44/45] Fix unit tests: use unique_ptr for BoundaryRegion/BoundaryRegionPar's --- tests/unit/field/test_vector2d.cxx | 9 --------- tests/unit/field/test_vector3d.cxx | 11 ----------- tests/unit/test_extras.hxx | 9 +++++---- 3 files changed, 5 insertions(+), 24 deletions(-) diff --git a/tests/unit/field/test_vector2d.cxx b/tests/unit/field/test_vector2d.cxx index 7824f2b2cf..1f77eb17c4 100644 --- a/tests/unit/field/test_vector2d.cxx +++ b/tests/unit/field/test_vector2d.cxx @@ -18,11 +18,6 @@ class Vector2DTest : public ::testing::Test { static void SetUpTestCase() { // Delete any existing mesh if (mesh != nullptr) { - // Delete boundary regions - for (auto &r : mesh->getBoundaries()) { - delete r; - } - delete mesh; mesh = nullptr; } @@ -39,10 +34,6 @@ class Vector2DTest : public ::testing::Test { static void TearDownTestCase() { if (mesh != nullptr) { - // Delete boundary regions - for (auto &r : mesh->getBoundaries()) { - delete r; - } delete mesh; mesh = nullptr; } diff --git a/tests/unit/field/test_vector3d.cxx b/tests/unit/field/test_vector3d.cxx index fb77078781..cac1439dec 100644 --- a/tests/unit/field/test_vector3d.cxx +++ b/tests/unit/field/test_vector3d.cxx @@ -17,11 +17,6 @@ class Vector3DTest : public ::testing::Test { static void SetUpTestCase() { // Delete any existing mesh if (mesh != nullptr) { - // Delete boundary regions - for (auto &r : mesh->getBoundaries()) { - delete r; - } - delete mesh; mesh = nullptr; } @@ -37,12 +32,6 @@ class Vector3DTest : public ::testing::Test { } static void TearDownTestCase() { - if (mesh != nullptr) { - // Delete boundary regions - for (auto &r : mesh->getBoundaries()) { - delete r; - } - } delete mesh; mesh = nullptr; } diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index becb73bcfd..2e27d9f066 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -144,9 +144,9 @@ public: const RangeIterator iterateBndryLowerInnerY() const { return RangeIterator(); } const RangeIterator iterateBndryUpperOuterY() const { return RangeIterator(); } const RangeIterator iterateBndryUpperInnerY() const { return RangeIterator(); } - void addBoundary(BoundaryRegion* region) {boundaries.push_back(region);} - vector getBoundaries() { return boundaries; } - vector getBoundariesPar() { return vector(); } + void addBoundary(BoundaryRegion* region) {boundaries.push_back(std::unique_ptr(region));} + vector< std::unique_ptr >& getBoundaries() { return boundaries; } + vector< std::unique_ptr >& getBoundariesPar() { return par_boundaries; } BoutReal GlobalX(int UNUSED(jx)) const { return 0; } BoutReal GlobalY(int UNUSED(jy)) const { return 0; } BoutReal GlobalZ(int UNUSED(jz)) const { return 0; } @@ -161,7 +161,8 @@ public: derivs_init(opt); } private: - vector boundaries; + vector< std::unique_ptr > boundaries; + vector< std::unique_ptr > par_boundaries; }; From d37335b6284bc26d80716a3d0aafacf9e9147e35 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 12 Nov 2018 18:54:38 +0000 Subject: [PATCH 45/45] Use shared_ptr for FieldData::bndry_op/bndry_op_par Removes need for boundaryIsCopy flag, as well as some loops that delete members of the vectors. --- include/field_data.hxx | 13 ++++++++----- src/field/field_data.cxx | 28 +++++----------------------- 2 files changed, 13 insertions(+), 28 deletions(-) diff --git a/include/field_data.hxx b/include/field_data.hxx index 5124726a92..ac03758bae 100644 --- a/include/field_data.hxx +++ b/include/field_data.hxx @@ -63,10 +63,10 @@ class FieldVisitor; class FieldData { public: FieldData(Mesh *datamesh = nullptr) - : fielddatamesh(datamesh != nullptr ? datamesh : mesh), boundaryIsCopy(false), + : fielddatamesh(datamesh != nullptr ? datamesh : mesh), boundaryIsSet(true) {} - virtual ~FieldData(); + virtual ~FieldData() {}; // Visitor pattern support virtual void accept(FieldVisitor &v) = 0; @@ -104,11 +104,14 @@ public: protected: Mesh* fielddatamesh; - vector bndry_op; ///< Boundary conditions - bool boundaryIsCopy; ///< True if bndry_op is a copy + + // use shared_ptr for bndry_op because if boundary conditions are copied from + // another field we want to share the pointers to the BoundaryOp objects in + // that field's bndry_op + vector< std::shared_ptr > bndry_op; ///< Boundary conditions bool boundaryIsSet; ///< Set to true when setBoundary called // Parallel boundaries - vector bndry_op_par; ///< Boundary conditions + vector< std::shared_ptr > bndry_op_par; ///< Boundary conditions std::map bndry_generator; }; diff --git a/src/field/field_data.cxx b/src/field/field_data.cxx index c5a5117ad1..49a20e543b 100644 --- a/src/field/field_data.cxx +++ b/src/field/field_data.cxx @@ -6,14 +6,6 @@ #include #include "unused.hxx" -FieldData::~FieldData() { - if(!boundaryIsCopy) { - // Delete the boundary operations - for(const auto& bndry : bndry_op) - delete bndry; - } -} - void FieldData::setBoundary(const string &name) { /// Get the boundary factory (singleton) BoundaryFactory *bfact = BoundaryFactory::getInstance(); @@ -21,35 +13,29 @@ void FieldData::setBoundary(const string &name) { output_info << "Setting boundary for variable " << name << endl; /// Get rid of existing boundary ops - for (auto &op : bndry_op) { - delete op; - } bndry_op.clear(); /// Loop over the mesh boundary regions for(const auto& reg : getDataMesh()->getBoundaries()) { BoundaryOp* op = bfact->createFromOptions(name, reg.get()); if (op != nullptr) - bndry_op.push_back(op); + bndry_op.push_back(std::shared_ptr(op)); output_info << endl; } /// Get rid of existing parallel boundary ops - for (auto &op : bndry_op_par) { - delete op; - } bndry_op_par.clear(); /// Loop over the mesh parallel boundary regions for(const auto& reg : getDataMesh()->getBoundariesPar()) { BoundaryOpPar* op = bfact->createFromOptions(name, reg.get()); - if (op != nullptr) - bndry_op_par.push_back(op); + if (op != nullptr) { + bndry_op_par.push_back(std::shared_ptr(op)); + } output_info << endl; } boundaryIsSet = true; - boundaryIsCopy = false; } void FieldData::setBoundary(const string ®ion, BoundaryOp *op) { @@ -71,9 +57,6 @@ void FieldData::setBoundary(const string ®ion, BoundaryOp *op) { output << "Replacing " << region_ptr->label<clone(region_ptr, {}, {}); - bndry_op.push_back(new_op); + bndry_op.push_back(std::shared_ptr(new_op)); } void FieldData::copyBoundary(const FieldData &f) { bndry_op = f.bndry_op; bndry_op_par = f.bndry_op_par; - boundaryIsCopy = true; boundaryIsSet = true; }