Conversation
Also add override keywords for GlobalX, GlobalY and GlobalZ in BoutMesh declaration.
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.
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.
Also move FieldData ctor into header
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().
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.
If fieldmesh needs to be set, so will fielddatamesh. Therefore set it to global mesh in allocate() if fieldmesh is being set.
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.
called "free_o4" and "free_o5".
Makes it consistent with standard naming scheme. Can be called with either option "dirichlet_o5" or (now deprecated) "dirichlet_4thorder".
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.
Apply x- and y-boundary conditions in MMS/derivatives3 to test their accuracy and correctness. Tests Dirichlet, Neumann and Free boundary conditions.
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.
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.
|
This should replace #1319. |
Does it take only a uniform dx/dy into account, or also a non-uniform dx/dy? I am asking, because to my understanding the others (I had a look at free, dirichlet, neumann) do not as far as I can tell, and that is why I added #1179 |
include/boundary_standard.hxx
Outdated
| void apply(Field3D &f) override; | ||
| void apply(Field3D &f,BoutReal t) override; | ||
| void apply(Field2D &f,BoutReal t = 0.) override { | ||
| applyTemplate<Field2D>(f, t); |
There was a problem hiding this comment.
You probably don't actually need to specify Field2D or Field3D here as the compiler should be able to infer the type, although being explicit certainly doesn't hurt.
@dschwoerer no, the Robin bc doesn't account for variation of dx/dy, just uses the value dx/dy at the boundary grid point. Sorry, I hadn't looked at #1179 before now. |
|
Sorry for the duplicate comments! |
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).
These were not needed because the compiler can infer the template arguments from the type (Field2D/Field3D) of the function argument.
Also change BoundaryRegionOp from using is_same to is_convertible, in case template needs to be used with subclasses of BoundaryRegion/BoundaryRegionPar.
|
@bendudson what is the reason for having the BoundaryWidth modifier? It's being trickier than I'd anticipated to update; understanding the purpose would help make sure I don't break anything... |
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
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
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<BoundaryRegion> bndry' which is copied from the input BoundaryRegion, but with the width changed.
1703fa2 to
ee9b86b
Compare
|
@johnomotani I'm a bit unsure what the purpose was of the width modifier, and since it doesn't seem to be used in any of the examples, it can probably be removed. At least I wouldn't worry too much about trying to preserve it. I think it was either for:
|
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.
In Mesh/BoutMesh keep boundary objects in a vector< std::unique_ptr<BoundaryRegion> > and vector< std::unique_ptr<BoundaryRegionPar> > instead of vector<BoundaryRegion*> and vector<BoundaryRegionPar*>.
ee9b86b to
ce640f0
Compare
This previously did nothing, although it is not used anywhere.
ce640f0 to
ebda6f3
Compare
|
Thanks @bendudson 👍 The tricky part about The neatest solution I've thought of is to use the A few other changes:
|
|
There was a comment in the manual about |
48af365 to
e153669
Compare
|
If you are not sure, could you not mention that at all?
Having wrong documentation is IMO way more confusing then no documentation.
I don't think BOUT++ generally makes any sort of guarantees in that
regard, thus saying one thing isn't thread safe implies the rest is -
which might be the case, but I don't know.
|
Removes need for boundaryIsCopy flag, as well as some loops that delete members of the vectors.
e153669 to
d37335b
Compare
|
@johnomotani do you still intend to follow up on this? |
No. I don't remember now what exactly the purpose was, so don't know if in principle it would be worth updating and merging. In any case I don't have any time to work on it now, so I'm not going to do anything. Anyone is welcome to take it over if they think it's useful, although at this point it might be easier to start over from scratch! |
Simplify boundary_standard.cxx:
BOUT-dev/src/mesh/boundary_standard.cxx
Lines 415 to 445 in cf7aa24
BoundaryDirichlet still has its own apply() method because it handled 2nd (and 3rd, 4th, etc.) guard cells in a non-standard way, setting them equal to the boundary value expression (evaluated at the guard cell's location); I have left this as-is. BoundaryNeumann_NonOrthogonal, BoundaryZeroLaplace, BoundaryZeroLaplace2 and BoundaryConstLaplace also implement overriding apply methods.
static_casts. Could undo this, but would take a little digging because I didn't do a good job of implementing this refactor in separate commits.Fixes a few bugs: setting boundary conditions for fields at CELL_ZLOW (previously this case fell though and the guard cells were not changed); use the fieldmesh of the field, not the global mesh, in all boundary conditions; correct one of the coefficients in
BoundaryDirichlet_4thOrder(now renamed toBoundaryDirichlet_O5; implement BoundaryNeumann_O4 for staggered grids.Add
GlobalZmethod to Mesh for consistency withGlobalX,GlobalY.Add a couple of higher order extrapolating boundary conditions,
free_o4andfree_o5.Change
BoundaryRobinto take account of grid spacing, so now the derivative coefficient passed in (b) does not have to include dx or dy. Effectively derivative in boundary condition is now DDX or DDY instead of indexDDX or indexDDY.Test the order of accuracy of Dirichlet, Neumann and free boundary conditions in MMS/derivatives3.
Add new boundary condition
dirichlet_smooth, which suppresses grid-scale oscillations at the boundary enough to be used inwave-1d/wave-1d-yMMS tests. It has the same accuracy as the standarddirichletcondition, but uses two grid points to set the boundary condition. Setting the guard cell g by extrapolating from the boundary value, v, and first grid cell, f1 would give 'g1 = 2v-f1'; setting from the second grid cell would give 'g2 = 4/3v-1/3f2'; this bc takes the average of the two, setting 'g = 4/3v-1/2f1-1/6f2'.Test both
dirichlet_smoothandneumannboundary conditions forStaggerGrids=trueorfalseinMMS/wave-1dandMMS/wave-1d-y.Test both
dirichletandneumannboundary conditions on both boundaries inMMS/diffusion.