Skip to content

Commit c99bf70

Browse files
authored
implement a FaceCenterData2d class (#70)
1 parent aa7d11e commit c99bf70

3 files changed

Lines changed: 858 additions & 4 deletions

File tree

mesh/array_indexer.py

Lines changed: 246 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@ def _buf_split(b):
2626

2727

2828
class ArrayIndexer(np.ndarray):
29-
""" a class that wraps the data region of a single array (d)
30-
and allows us to easily do array operations like d[i+1,j]
31-
using the ip() method. """
29+
"""a class that wraps the data region of a single cell-centered data
30+
array (d) and allows us to easily do array operations like
31+
d[i+1,j] using the ip() method.
32+
33+
"""
3234

3335
def __new__(self, d, grid=None):
3436
obj = np.asarray(d).view(self)
@@ -331,3 +333,244 @@ def pretty_print(self, n=0, fmt=None, show_ghost=True):
331333
+---> x
332334
"""
333335
print(leg)
336+
337+
338+
class ArrayIndexerFC(ArrayIndexer):
339+
"""a class that wraps the data region of a single face-centered data
340+
array (d) and allows us to easily do array operations like
341+
d[i+1,j] using the ip() method.
342+
343+
"""
344+
345+
def __new__(self, d, idir, grid=None):
346+
obj = np.asarray(d).view(self)
347+
obj.g = grid
348+
obj.idir = idir
349+
obj.c = len(d.shape)
350+
351+
return obj
352+
353+
def __array_finalize__(self, obj):
354+
if obj is None:
355+
return
356+
self.g = getattr(obj, "g", None)
357+
self.idir = getattr(obj, "idir", None)
358+
self.c = getattr(obj, "c", None)
359+
360+
def __array_wrap__(self, out_arr, context=None):
361+
return np.ndarray.__array_wrap__(self, out_arr, context)
362+
363+
def ip_jp(self, ishift, jshift, buf=0, n=0, s=1):
364+
"""return a view of the data shifted by ishift in the x direction and
365+
jshift in the y direction. By default the view is the same
366+
size as the valid region, but the buf can specify how many
367+
ghost cells on each side to include. The component is n and s
368+
is the stride
369+
370+
"""
371+
bxlo, bxhi, bylo, byhi = _buf_split(buf)
372+
c = len(self.shape)
373+
374+
if self.idir == 1:
375+
# face-centered in x
376+
if c == 2:
377+
return np.asarray(self[self.g.ilo-bxlo+ishift:self.g.ihi+2+bxhi+ishift:s,
378+
self.g.jlo-bylo+jshift:self.g.jhi+1+byhi+jshift:s])
379+
else:
380+
return np.asarray(self[self.g.ilo-bxlo+ishift:self.g.ihi+2+bxhi+ishift:s,
381+
self.g.jlo-bylo+jshift:self.g.jhi+1+byhi+jshift:s, n])
382+
elif self.idir == 2:
383+
# face-centered in y
384+
if c == 2:
385+
return np.asarray(self[self.g.ilo-bxlo+ishift:self.g.ihi+1+bxhi+ishift:s,
386+
self.g.jlo-bylo+jshift:self.g.jhi+2+byhi+jshift:s])
387+
else:
388+
return np.asarray(self[self.g.ilo-bxlo+ishift:self.g.ihi+1+bxhi+ishift:s,
389+
self.g.jlo-bylo+jshift:self.g.jhi+2+byhi+jshift:s, n])
390+
391+
def lap(self, n=0, buf=0):
392+
raise NotImplementedError("lap not implemented for ArrayIndexerFC")
393+
394+
def norm(self, n=0):
395+
"""
396+
find the norm of the quantity (index n) defined on the same grid,
397+
in the domain's valid region
398+
399+
"""
400+
c = len(self.shape)
401+
if self.idir == 1:
402+
if c == 2:
403+
return np.sqrt(self.g.dx * self.g.dy *
404+
np.sum((self[self.g.ilo:self.g.ihi+2, self.g.jlo:self.g.jhi+1]**2).flat))
405+
406+
else:
407+
_tmp = self[:, :, n]
408+
return np.sqrt(self.g.dx * self.g.dy *
409+
np.sum((_tmp[self.g.ilo:self.g.ihi+2, self.g.jlo:self.g.jhi+1]**2).flat))
410+
elif self.idir == 2:
411+
if c == 2:
412+
return np.sqrt(self.g.dx * self.g.dy *
413+
np.sum((self[self.g.ilo:self.g.ihi+1, self.g.jlo:self.g.jhi+2]**2).flat))
414+
415+
else:
416+
_tmp = self[:, :, n]
417+
return np.sqrt(self.g.dx * self.g.dy *
418+
np.sum((_tmp[self.g.ilo:self.g.ihi+1, self.g.jlo:self.g.jhi+2]**2).flat))
419+
420+
def copy(self):
421+
"""make a copy of the array, defined on the same grid"""
422+
return ArrayIndexer(np.asarray(self).copy(), self.idir, grid=self.g)
423+
424+
def is_symmetric(self, nodal=False, tol=1.e-14, asymmetric=False):
425+
"""return True is the data is left-right symmetric (to the tolerance
426+
tol) For node-centered data, set nodal=True
427+
428+
"""
429+
raise NotImplementedError()
430+
431+
def is_asymmetric(self, nodal=False, tol=1.e-14):
432+
"""return True is the data is left-right asymmetric (to the tolerance
433+
tol)---e.g, the sign flips. For node-centered data, set nodal=True
434+
435+
"""
436+
raise NotImplementedError()
437+
438+
def fill_ghost(self, n=0, bc=None):
439+
"""Fill the boundary conditions. This operates on a single component,
440+
n. We do periodic, reflect-even, reflect-odd, and outflow
441+
442+
We need a BC object to tell us what BC type on each boundary.
443+
"""
444+
445+
# there is only a single grid, so every boundary is on
446+
# a physical boundary (except if we are periodic)
447+
448+
# Note: we piggy-back on outflow and reflect-odd for
449+
# Neumann and Dirichlet homogeneous BCs respectively, but
450+
# this only works for a single ghost cell
451+
452+
# -x boundary
453+
if bc.xlb in ["outflow", "neumann", "reflect-even", "reflect-odd", "dirichlet"]:
454+
raise NotImplementedError("boundary condition not implemented for -x")
455+
elif bc.xlb == "periodic":
456+
if self.idir == 1:
457+
# face-centered in x
458+
for i in range(self.g.ilo):
459+
self[i, :, n] = self[self.g.ihi-self.g.ng+i+1, :, n]
460+
elif self.idir == 2:
461+
# face-centered in y
462+
for i in range(self.g.ilo):
463+
self[i, :, n] = self[self.g.ihi-self.g.ng+i+1, :, n]
464+
465+
# +x boundary
466+
if bc.xrb in ["outflow", "neumann", "reflect-even", "reflect-odd", "dirichlet"]:
467+
raise NotImplementedError("boundary condition not implemented for +x")
468+
elif bc.xrb == "periodic":
469+
if self.idir == 1:
470+
# face-centered in x
471+
for i in range(self.g.ihi+2, 2*self.g.ng + self.g.nx + 1):
472+
self[i, :, n] = self[i-self.g.ihi-1+self.g.ng, :, n]
473+
elif self.idir == 2:
474+
# face-centered in y
475+
for i in range(self.g.ihi+1, 2*self.g.ng + self.g.nx):
476+
self[i, :, n] = self[i-self.g.ihi-1+self.g.ng, :, n]
477+
478+
# -y boundary
479+
if bc.ylb in ["outflow", "neumann", "reflect-even", "reflect-odd", "dirichlet"]:
480+
raise NotImplementedError("boundary condition not implemented for -y")
481+
elif bc.ylb == "periodic":
482+
if self.idir == 1:
483+
# face-centered in x
484+
for j in range(self.g.jlo):
485+
self[:, j, n] = self[:, self.g.jhi-self.g.ng+j+1, n]
486+
elif self.idir == 2:
487+
# face-centered in y
488+
for j in range(self.g.jlo):
489+
self[:, j, n] = self[:, self.g.jhi-self.g.ng+j+1, n]
490+
491+
# +y boundary
492+
if bc.yrb in ["outflow", "neumann", "reflect-even", "reflect-odd", "dirichlet"]:
493+
raise NotImplementedError("boundary condition not implemented for +y")
494+
elif bc.yrb == "periodic":
495+
if self.idir == 1:
496+
# face-centered in x
497+
for j in range(self.g.jhi+1, 2*self.g.ng + self.g.ny):
498+
self[:, j, n] = self[:, j-self.g.jhi-1+self.g.ng, n]
499+
elif self.idir == 2:
500+
for j in range(self.g.jhi+2, 2*self.g.ng + self.g.ny + 1):
501+
self[:, j, n] = self[:, j-self.g.jhi-1+self.g.ng, n]
502+
503+
def pretty_print(self, n=0, fmt=None, show_ghost=True):
504+
"""
505+
Print out a small dataset to the screen with the ghost cells
506+
a different color, to make things stand out
507+
"""
508+
509+
if fmt is None:
510+
if self.dtype == np.int:
511+
fmt = "%4d"
512+
elif self.dtype == np.float64:
513+
fmt = "%10.5g"
514+
else:
515+
raise ValueError("ERROR: dtype not supported")
516+
517+
# print j descending, so it looks like a grid (y increasing
518+
# with height)
519+
if show_ghost:
520+
if self.idir == 1:
521+
ilo = 0
522+
ihi = self.g.qx
523+
jlo = 0
524+
jhi = self.g.qy-1
525+
elif self.idir == 2:
526+
ilo = 0
527+
ihi = self.g.qx-1
528+
jlo = 0
529+
jhi = self.g.qy
530+
531+
else:
532+
if self.idir == 1:
533+
ilo = self.g.ilo
534+
ihi = self.g.ihi+1
535+
jlo = self.g.jlo
536+
jhi = self.g.jhi
537+
elif self.idir == 2:
538+
ilo = self.g.ilo
539+
ihi = self.g.ihi
540+
jlo = self.g.jlo
541+
jhi = self.g.jhi+1
542+
543+
for j in reversed(range(jlo, jhi+1)):
544+
for i in range(ilo, ihi+1):
545+
546+
if self.idir == 1:
547+
if (j < self.g.jlo or j > self.g.jhi or
548+
i < self.g.ilo or i > self.g.ihi+1):
549+
gc = 1
550+
else:
551+
gc = 0
552+
elif self.idir == 2:
553+
if (j < self.g.jlo or j > self.g.jhi+1 or
554+
i < self.g.ilo or i > self.g.ihi):
555+
gc = 1
556+
else:
557+
gc = 0
558+
559+
if self.c == 2:
560+
val = self[i, j]
561+
else:
562+
val = self[i, j, n]
563+
564+
if gc:
565+
print("\033[31m" + fmt % (val) + "\033[0m", end="")
566+
else:
567+
print(fmt % (val), end="")
568+
569+
print(" ")
570+
571+
leg = """
572+
^ y
573+
|
574+
+---> x
575+
"""
576+
print(leg)

0 commit comments

Comments
 (0)