@@ -116,6 +116,135 @@ void verifyNumPoints(BoundaryRegion* region, int ptsRequired) {
116116void verifyNumPoints (BoundaryRegion*, int ) {}
117117#endif
118118
119+
120+ // /////////////////////////////////////////////////////////////
121+
122+ BoundaryOp* BoundaryDirichlet_O1::clone (BoundaryRegion* region,
123+ const std::list<std::string>& args) {
124+ verifyNumPoints (region, 1 );
125+
126+ std::shared_ptr<FieldGenerator> newgen;
127+ if (!args.empty ()) {
128+ // First argument should be an expression
129+ newgen = FieldFactory::get ()->parse (args.front ());
130+ }
131+ return new BoundaryDirichlet_O1 (region, newgen);
132+ }
133+
134+ void BoundaryDirichlet_O1::apply (Field2D& f) { BoundaryDirichlet_O1::apply (f, 0 .); }
135+
136+ void BoundaryDirichlet_O1::apply (Field2D& f, BoutReal t) {
137+ // Set (at 1st order) the value at the grid cell to the guard cells.
138+
139+ Mesh* mesh = bndry->localmesh ;
140+ ASSERT1 (mesh == f.getMesh ());
141+ bndry->first ();
142+
143+ // Decide which generator to use
144+ std::shared_ptr<FieldGenerator> fg = gen;
145+ if (!fg) {
146+ fg = f.getBndryGenerator (bndry->location );
147+ }
148+
149+ BoutReal val = 0.0 ;
150+
151+ // Check for staggered grids
152+
153+ CELL_LOC loc = f.getLocation ();
154+ if (mesh->StaggerGrids ) {
155+ // Staggered
156+ throw BoutException (" dirichlet_o1 BC is not implementated for staggered grids." );
157+
158+ } else {
159+ // Non-staggered, standard case
160+ for (; !bndry->isDone (); bndry->next1d ()) {
161+
162+ if (fg) {
163+ val = fg->generate (Context (bndry, loc, t, mesh));
164+ }
165+ f (bndry->x , bndry->y ) = val;
166+
167+ // Need to set second guard cell, as may be used for interpolation or upwinding derivatives
168+ // This is not very efficient. Both boundary cells can be treated in one loop.
169+ for (int i = 1 ; i < bndry->width ; i++) {
170+ int xi = bndry->x + i * bndry->bx ;
171+ int yi = bndry->y + i * bndry->by ;
172+ f (xi, yi) = val;
173+ }
174+
175+ }
176+ }
177+ }
178+
179+ void BoundaryDirichlet_O1::apply (Field3D& f) { BoundaryDirichlet_O1::apply (f, 0 .); }
180+
181+ void BoundaryDirichlet_O1::apply (Field3D& f, BoutReal t) {
182+ // Set (at 1st order) the value at the grid cell to the guard cells.
183+
184+ Mesh* mesh = bndry->localmesh ;
185+ ASSERT1 (mesh == f.getMesh ());
186+ bndry->first ();
187+
188+ // Decide which generator to use
189+ std::shared_ptr<FieldGenerator> fg = gen;
190+ if (!fg) {
191+ fg = f.getBndryGenerator (bndry->location );
192+ }
193+
194+ BoutReal val = 0.0 ;
195+
196+ // Check for staggered grids
197+
198+ CELL_LOC loc = f.getLocation ();
199+ if (mesh->StaggerGrids ) {
200+ // Staggered.
201+ throw BoutException (" dirichlet_o1 BC is not implementated for staggered grids." );
202+
203+ } else {
204+ // Standard (non-staggered) case
205+ for (; !bndry->isDone (); bndry->next1d ()) {
206+ for (int zk = 0 ; zk < mesh->LocalNz ; zk++) {
207+ if (fg) {
208+ val = fg->generate (Context (bndry, zk, loc, t, mesh));
209+ }
210+ f (bndry->x , bndry->y , zk) = val;
211+ }
212+
213+ // This is not very efficient. Both boundary cells can be treated in one loop.
214+ for (int i = 1 ; i < bndry->width ; i++) {
215+ // Set any other guard cells using the values on the cells
216+ int xi = bndry->x + i * bndry->bx ;
217+ int yi = bndry->y + i * bndry->by ;
218+ for (int zk = 0 ; zk < mesh->LocalNz ; zk++) {
219+ if (fg) {
220+ val = fg->generate (Context (bndry, zk, loc, t, mesh));
221+ }
222+ f (xi, yi, zk) = val;
223+ }
224+ }
225+ }
226+ }
227+ }
228+
229+ void BoundaryDirichlet_O1::apply_ddt (Field2D& f) {
230+ Field2D* dt = f.timeDeriv ();
231+ for (bndry->first (); !bndry->isDone (); bndry->next ()) {
232+ (*dt)(bndry->x , bndry->y ) = 0 .; // Set time derivative to zero
233+ }
234+ }
235+
236+ void BoundaryDirichlet_O1::apply_ddt (Field3D& f) {
237+ Mesh* mesh = bndry->localmesh ;
238+ ASSERT1 (mesh == f.getMesh ());
239+ Field3D* dt = f.timeDeriv ();
240+
241+ for (bndry->first (); !bndry->isDone (); bndry->next ()) {
242+ for (int z = 0 ; z < mesh->LocalNz ; z++) {
243+ (*dt)(bndry->x , bndry->y , z) = 0 .; // Set time derivative to zero
244+ }
245+ }
246+ }
247+
119248// /////////////////////////////////////////////////////////////
120249
121250BoundaryOp* BoundaryDirichlet::clone (BoundaryRegion* region,
@@ -1715,6 +1844,138 @@ void BoundaryNeumann_NonOrthogonal::apply(Field3D& f) {
17151844
17161845 // /////////////////////////////////////////////////////////////
17171846
1847+ BoundaryOp* BoundaryNeumann_O1::clone (BoundaryRegion * region,
1848+ const std::list<std::string>& args) {
1849+ verifyNumPoints (region, 1 );
1850+ std::shared_ptr<FieldGenerator> newgen = nullptr ;
1851+ if (!args.empty ()) {
1852+ // First argument should be an expression
1853+ newgen = FieldFactory::get ()->parse (args.front ());
1854+ }
1855+ return new BoundaryNeumann_O1 (region, newgen);
1856+ }
1857+
1858+ void BoundaryNeumann_O1::apply (Field2D & f) { BoundaryNeumann_O1::apply (f, 0 .); }
1859+
1860+ void BoundaryNeumann_O1::apply (Field2D & f, BoutReal t) {
1861+ // Set (at 1st order) the gradient/value at the grid cell to the guard cells.
1862+
1863+
1864+ #if not(BOUT_USE_METRIC_3D)
1865+ Mesh* mesh = bndry->localmesh ;
1866+ ASSERT1 (mesh == f.getMesh ());
1867+ Coordinates* metric = f.getCoordinates ();
1868+
1869+ bndry->first ();
1870+
1871+ // Decide which generator to use
1872+ std::shared_ptr<FieldGenerator> fg = gen;
1873+ if (!fg) {
1874+ fg = f.getBndryGenerator (bndry->location );
1875+ }
1876+
1877+ BoutReal val = 0.0 ;
1878+
1879+ // Check for staggered grids
1880+
1881+ CELL_LOC loc = f.getLocation ();
1882+ if (mesh->StaggerGrids ) {
1883+ // Staggered.
1884+ throw BoutException (" neumann_o1 BC is not implementated for staggered grids." );
1885+
1886+ } else {
1887+ // Non-staggered, standard case
1888+
1889+ for (bndry->first (); !bndry->isDone (); bndry->next1d ()) {
1890+ BoutReal delta = bndry->bx * metric->dx (bndry->x , bndry->y )
1891+ + bndry->by * metric->dy (bndry->x , bndry->y );
1892+
1893+ if (fg) {
1894+ val = fg->generate (Context (bndry, loc, t, mesh));
1895+ }
1896+
1897+ f (bndry->x , bndry->y ) =
1898+ f (bndry->x - bndry->bx , bndry->y - bndry->by ) + delta * val;
1899+ if (bndry->width == 2 ) {
1900+ f (bndry->x + bndry->bx , bndry->y + bndry->by ) = f (bndry->x , bndry->y ) + delta * val;
1901+ }
1902+ }
1903+ }
1904+ #else
1905+ throw BoutException (" Applying boundary condition 'neumann' to Field2D "
1906+ " not compatible with 3D metrics in all cases." );
1907+ #endif
1908+ }
1909+
1910+ void BoundaryNeumann_O1::apply (Field3D & f) { BoundaryNeumann_O1::apply (f, 0 .); }
1911+
1912+ void BoundaryNeumann_O1::apply (Field3D & f, BoutReal t) {
1913+ Mesh* mesh = bndry->localmesh ;
1914+ ASSERT1 (mesh == f.getMesh ());
1915+ Coordinates* metric = f.getCoordinates ();
1916+
1917+ bndry->first ();
1918+
1919+ // Decide which generator to use
1920+ std::shared_ptr<FieldGenerator> fg = gen;
1921+ if (!fg) {
1922+ fg = f.getBndryGenerator (bndry->location );
1923+ }
1924+
1925+ BoutReal val = 0.0 ;
1926+
1927+ // Check for staggered grids
1928+
1929+ CELL_LOC loc = f.getLocation ();
1930+ if (mesh->StaggerGrids ) {
1931+ // Staggered.
1932+ throw BoutException (" neumann_o1 BC is not implementated for staggered grids." );
1933+
1934+ } else {
1935+ for (; !bndry->isDone (); bndry->next1d ()) {
1936+ #if BOUT_USE_METRIC_3D
1937+ for (int zk = 0 ; zk < mesh->LocalNz ; zk++) {
1938+ BoutReal delta = bndry->bx * metric->dx (bndry->x , bndry->y , zk)
1939+ + bndry->by * metric->dy (bndry->x , bndry->y , zk);
1940+ #else
1941+ BoutReal delta = bndry->bx * metric->dx (bndry->x , bndry->y )
1942+ + bndry->by * metric->dy (bndry->x , bndry->y );
1943+ for (int zk = 0 ; zk < mesh->LocalNz ; zk++) {
1944+ #endif
1945+ if (fg) {
1946+ val = fg->generate (Context (bndry, zk, loc, t, mesh));
1947+ }
1948+ f (bndry->x , bndry->y , zk) =
1949+ f (bndry->x - bndry->bx , bndry->y - bndry->by , zk) + delta * val;
1950+ if (bndry->width == 2 ) {
1951+ f (bndry->x + bndry->bx , bndry->y + bndry->by , zk) =
1952+ f (bndry->x , bndry->y , zk) + delta * val;
1953+ }
1954+ }
1955+ }
1956+ }
1957+ }
1958+
1959+ void BoundaryNeumann_O1::apply_ddt (Field2D & f) {
1960+ Field2D* dt = f.timeDeriv ();
1961+ for (bndry->first (); !bndry->isDone (); bndry->next ()) {
1962+ (*dt)(bndry->x , bndry->y ) = 0 .; // Set time derivative to zero
1963+ }
1964+ }
1965+
1966+ void BoundaryNeumann_O1::apply_ddt (Field3D & f) {
1967+ Mesh* mesh = bndry->localmesh ;
1968+ ASSERT1 (mesh == f.getMesh ());
1969+ Field3D* dt = f.timeDeriv ();
1970+ for (bndry->first (); !bndry->isDone (); bndry->next ()) {
1971+ for (int z = 0 ; z < mesh->LocalNz ; z++) {
1972+ (*dt)(bndry->x , bndry->y , z) = 0 .; // Set time derivative to zero
1973+ }
1974+ }
1975+ }
1976+
1977+ // /////////////////////////////////////////////////////////////
1978+
17181979 BoundaryOp* BoundaryNeumann::clone (BoundaryRegion * region,
17191980 const std::list<std::string>& args) {
17201981 verifyNumPoints (region, 1 );
0 commit comments