Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Octree ghost zones — reloaded #2425

Merged
merged 65 commits into from
Jul 19, 2020
Merged
Show file tree
Hide file tree
Changes from 47 commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
333436c
Add support for fast neighbour search
cphyc Jan 21, 2020
6ce0416
More generic code
cphyc Jan 22, 2020
2b0baa3
Remove useless variable on oct container
cphyc Jan 22, 2020
8cf8a56
First working (not crashing version)
cphyc Jan 22, 2020
ab4410e
Does not work yet, but hey it compiles
cphyc Jun 17, 2020
b7c0c2f
Wiring cython code with ghost zones
cphyc Jan 22, 2020
8da0a17
Cleanup
cphyc Jan 22, 2020
adb21ba
First working (not crashing) version
cphyc Jan 23, 2020
bc077f4
Fix octree accessor
cphyc Jan 23, 2020
266ac1f
Forget about nan when doing gradients
cphyc Jun 17, 2020
0d8bf3a
Accept unyt_array as center
cphyc Jan 23, 2020
59923e2
Gradient should be block order-aware
cphyc Jun 17, 2020
6d091d5
cAdd comments
cphyc Jan 23, 2020
08fe5a9
Support reading boundaries between CPUs
cphyc Jan 23, 2020
d6b508b
Filling hydro with boundary information
cphyc Jan 28, 2020
fb6462a
Use Fortran ordering to read in for faster results
cphyc Jan 30, 2020
d23b9a1
Working version?
cphyc Jan 30, 2020
5859895
Correct erroneous reference
cphyc Jan 30, 2020
cac9d19
Catch early bug
cphyc Jan 30, 2020
dbeccb8
More explicit names
cphyc Jan 30, 2020
2ddaebb
Correct discrepancy between .pxd and .pyx file
cphyc Jan 30, 2020
3c20d53
UNSURE ABOUT THIS ONE, REMOVE ME IF YOU HAVE WEIRD RESULTS
cphyc Jan 30, 2020
1265769
Read boundary regions as well
cphyc Jan 30, 2020
41f0501
Cannot assume that keys are string by default (can be tuple)
cphyc Jan 30, 2020
a39b4e7
Inform gradient about ordering
cphyc Jan 30, 2020
463cd9a
Use less ambiguous name
cphyc Jun 17, 2020
295695e
Use block_reorder to decide when transposing
cphyc Jan 30, 2020
9c04156
("index, "ones") should return data with units
cphyc Jan 30, 2020
7c8fe2f
Add unit test
cphyc Jun 17, 2020
c42a2fb
Add new answer test
cphyc Jan 30, 2020
7a7807d
Move non-specific code into oct_container.pyx
cphyc Jan 30, 2020
4fa0a57
Remove unused parent accessor
cphyc Jan 30, 2020
9b4e5c7
RAMSES octree is sparse, restore this
cphyc Jan 30, 2020
b5b2bfa
Update docstring
cphyc Jan 30, 2020
c3262c7
Only query fcoords w/o ghost zones
cphyc Feb 8, 2020
5e5af6f
Assume periodicity
cphyc Feb 11, 2020
7266517
Add warning
cphyc Feb 11, 2020
9fc52df
Vastly simplify code
cphyc Feb 12, 2020
8ec0354
Remove useless import
cphyc Feb 12, 2020
aa2605d
Remove unused visitor
cphyc Feb 12, 2020
11285a0
Remove useless method
cphyc Feb 19, 2020
6fde2e5
Address comments
cphyc May 29, 2020
b918389
Fix mistake
cphyc Jun 17, 2020
7978ddc
No need to format warning
cphyc Jun 17, 2020
86a314e
regenerate answers
cphyc Jun 23, 2020
6d4adf8
Support non periodic boundaries?
cphyc Jun 23, 2020
d4ecca3
Merge branch 'master' into neighbour-search
cphyc Jun 26, 2020
6c318dc
Add kwa to select calls
cphyc Jul 2, 2020
236134b
ds → dx
cphyc Jul 2, 2020
550e887
Return "arr" not "tmp" variable
cphyc Jul 2, 2020
0fc5131
Each line for its argument
cphyc Jul 2, 2020
f7d9e4a
Minor nits in docstrings
cphyc Jul 2, 2020
9ca0d0e
Using python-friendly syntax
cphyc Jul 2, 2020
a92d477
Remove duplicates in testing file
cphyc Jul 2, 2020
58f4384
Merge
cphyc Jul 2, 2020
0bf76b2
_block_reorder -> _block_order
cphyc Jul 2, 2020
19058d8
Field detector does not have a block_order argument
cphyc Jul 2, 2020
6d2b439
Reorder if necessary
cphyc Jul 3, 2020
f21e058
Merge branch 'master' into neighbour-search
cphyc Jul 16, 2020
3c8b75c
Take comments into account
cphyc Jul 17, 2020
13e5dfa
Inform Cython about strides
cphyc Jul 17, 2020
d97eb12
Merge
cphyc Jul 17, 2020
b199540
tr -> data
cphyc Jul 18, 2020
8ecce95
Make isort happy
cphyc Jul 18, 2020
c033f18
Fix flaking
cphyc Jul 18, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion tests/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ answer_tests:
- yt/frontends/boxlib/tests/test_outputs.py:test_NyxDataset
- yt/frontends/boxlib/tests/test_outputs.py:test_WarpXDataset

local_ramses_002:
local_ramses_003:
- yt/frontends/ramses/tests/test_outputs.py:test_output_00080

local_ytdata_007:
Expand Down
12 changes: 5 additions & 7 deletions yt/data_objects/data_containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -352,13 +352,11 @@ def _generate_spatial_fluid(self, field, ngz):
rv = self.ds.arr(np.empty(wogz.ires.size,
dtype="float64"), units)
outputs.append(rv)
if gz._type_name == 'octree_subset':
raise NotImplementedError
else:
ind += wogz.select(
self.selector,
gz[field][ngz:-ngz, ngz:-ngz, ngz:-ngz],
rv, ind)
data = gz[field][ngz:-ngz, ngz:-ngz, ngz:-ngz]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like getting rid of the conditional! Nice.

ind += wogz.select(
self.selector,
data,
rv, ind)
cphyc marked this conversation as resolved.
Show resolved Hide resolved
if accumulate:
rv = uconcatenate(outputs)
return rv
Expand Down
3 changes: 2 additions & 1 deletion yt/data_objects/octree_subset.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,10 @@ class OctreeSubset(YTSelectionContainer):
_cell_count = -1
_block_reorder = None

def __init__(self, base_region, domain, ds, over_refine_factor = 1):
def __init__(self, base_region, domain, ds, over_refine_factor = 1, num_ghost_zones = 0):
super(OctreeSubset, self).__init__(ds, None)
self._num_zones = 1 << (over_refine_factor)
self._num_ghost_zones = num_ghost_zones
self._oref = over_refine_factor
self.domain = domain
self.domain_id = domain.domain_id
Expand Down
23 changes: 16 additions & 7 deletions yt/fields/fluid_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def _cell_mass(field, data):
def _sound_speed(field, data):
tr = data.ds.gamma * data[ftype, "pressure"] / data[ftype, "density"]
return np.sqrt(tr)

registry.add_field((ftype, "sound_speed"),
sampling_type="local",
function=_sound_speed,
Expand All @@ -75,7 +75,7 @@ def _radial_mach_number(field, data):
""" Radial component of M{|v|/c_sound} """
tr = data[ftype, "radial_velocity"] / data[ftype, "sound_speed"]
return np.abs(tr)

registry.add_field((ftype, "radial_mach_number"),
sampling_type="local",
function=_radial_mach_number,
Expand All @@ -93,7 +93,7 @@ def _kin_energy(field, data):
def _mach_number(field, data):
""" M{|v|/c_sound} """
return data[ftype, "velocity_magnitude"] / data[ftype, "sound_speed"]

registry.add_field((ftype, "mach_number"),
sampling_type="local",
function=_mach_number,
Expand Down Expand Up @@ -189,7 +189,7 @@ def setup_gradient_fields(registry, grad_field, field_units, slice_info = None):

geom = registry.ds.geometry
if is_curvilinear(geom):
mylog.warning("In %s geometry, gradient fields may contain artifacts near cartesian axes." % geom)
mylog.warning("In %s geometry, gradient fields may contain artifacts near cartesian axes.", geom)

assert(isinstance(grad_field, tuple))
ftype, fname = grad_field
Expand All @@ -205,16 +205,25 @@ def grad_func(axi, ax):
slice_3dl = slice_3d[:axi] + (sl_left,) + slice_3d[axi+1:]
slice_3dr = slice_3d[:axi] + (sl_right,) + slice_3d[axi+1:]
def func(field, data):
block_reorder = getattr(data, '_block_reorder', None)
if block_reorder == 'F':
cphyc marked this conversation as resolved.
Show resolved Hide resolved
field_data = data[grad_field].swapaxes(0, 2)
cphyc marked this conversation as resolved.
Show resolved Hide resolved
else:
field_data = data[grad_field]
ds = div_fac * data[ftype, "d%s" % ax]
cphyc marked this conversation as resolved.
Show resolved Hide resolved
if ax == "theta":
ds *= data[ftype, "r"]
if ax == "phi":
ds *= data[ftype, "r"] * np.sin(data[ftype, "theta"])
f = data[grad_field][slice_3dr]/ds[slice_3d]
f -= data[grad_field][slice_3dl]/ds[slice_3d]
f = field_data[slice_3dr]/ds[slice_3d]
f -= field_data[slice_3dl]/ds[slice_3d]
new_field = np.zeros_like(data[grad_field], dtype=np.float64)
new_field = data.ds.arr(new_field, f.units)
new_field = data.ds.arr(new_field, field_data.units / ds.units)
cphyc marked this conversation as resolved.
Show resolved Hide resolved
new_field[slice_3d] = f

if block_reorder == 'F':
cphyc marked this conversation as resolved.
Show resolved Hide resolved
new_field = new_field.swapaxes(0, 2)

return new_field
return func

Expand Down
5 changes: 3 additions & 2 deletions yt/fields/geometric_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,10 @@ def _zeros(field, data):
def _ones(field, data):
"""Returns one for all cells"""
arr = np.ones(data.ires.shape, dtype="float64")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be

Suggested change
arr = np.ones(data.ires.shape, dtype="float64")
arr = np.ones_like(data.ires, dtype="float64")

?

tmp = data.apply_units(arr, field.units)
if data._spatial:
return data._reshape_vals(arr)
return data.apply_units(arr, field.units)
return data._reshape_vals(tmp)
return tmp
cphyc marked this conversation as resolved.
Show resolved Hide resolved

registry.add_field(("index", "ones"),
sampling_type="cell",
Expand Down
99 changes: 95 additions & 4 deletions yt/frontends/ramses/data_structures.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import os
import numpy as np
import weakref
import warnings
from collections import defaultdict
from glob import glob

Expand All @@ -9,6 +10,7 @@
setdefaultattr
from yt.geometry.oct_geometry_handler import \
OctreeIndex

from yt.geometry.geometry_handler import \
YTDataChunk
from yt.data_objects.static_output import \
Expand Down Expand Up @@ -181,7 +183,22 @@ class RAMSESDomainSubset(OctreeSubset):
_domain_offset = 1
_block_reorder = "F"

def fill(self, fd, fields, selector, file_handler):
_base_domain = None

def __init__(self, base_region, domain, ds, over_refine_factor=1, num_ghost_zones=0,
base_grid=None):
super(RAMSESDomainSubset, self).__init__(base_region, domain, ds, over_refine_factor, num_ghost_zones)

cphyc marked this conversation as resolved.
Show resolved Hide resolved
self._base_grid = base_grid

if num_ghost_zones > 0:
if not all(ds.periodicity):
warnings.warn('Ghost zones will wrongly assume the domain to be periodic.')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a reason this is not a logger warning ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I changed it to raise a RuntimeError unless there's a better one to raise here?

# Create a base domain *with no self._base_domain.fwidth
base_domain = RAMSESDomainSubset(ds.all_data(), domain, ds, over_refine_factor)
self._base_domain = base_domain

def _fill_no_ghostzones(self, fd, fields, selector, file_handler):
ndim = self.ds.dimensionality
# Here we get a copy of the file, which we skip through and read the
# bits we want.
Expand All @@ -197,13 +214,85 @@ def fill(self, fd, fields, selector, file_handler):
# Initializing data container
for field in fields:
tr[field] = np.zeros(cell_count, 'float64')

fill_hydro(fd, file_handler.offset,
file_handler.level_count, levels, cell_inds,
file_handler.level_count,
[self.domain_id-1],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

had to swim back to understand what this argument represents. It's probably obvious after a while but I don't think an inline comment would hurt ! (or explicit keyword syntax ? but I don't know if that's supported for Cython functions)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made the name of the variable explicit here and below (the next fill_hydro occurrence).

levels, cell_inds,
file_inds, ndim, all_fields, fields, tr,
oct_handler)
return tr

def _fill_with_ghostzones(self, fd, fields, selector, file_handler, num_ghost_zones):
ndim = self.ds.dimensionality
ncpu = self.ds.parameters['ncpu']
# Here we get a copy of the file, which we skip through and read the
# bits we want.
oct_handler = self.oct_handler
all_fields = [f for ft, f in file_handler.field_list]
fields = [f for ft, f in fields]
tr = {}
cphyc marked this conversation as resolved.
Show resolved Hide resolved

cell_count = selector.count_octs(self.oct_handler, self.domain_id) * self.nz**ndim

levels, cell_inds, file_inds, domains = self.oct_handler.file_index_octs_with_ghost_zones(
selector, self.domain_id, cell_count)

# Initializing data container
for field in fields:
tr[field] = np.zeros(cell_count, 'float64')
fill_hydro(fd, file_handler.offset,
file_handler.level_count,
list(range(ncpu)),
levels, cell_inds,
file_inds, ndim, all_fields, fields, tr,
oct_handler,
domains=domains)
return tr

@property
def fwidth(self):
fwidth = super(RAMSESDomainSubset, self).fwidth
if self._num_ghost_zones > 0:
fwidth = fwidth.reshape(-1, 8, 3)
n_oct = fwidth.shape[0]
new_fwidth = np.zeros((n_oct, self.nz**3, 3), dtype=fwidth.dtype)
new_fwidth[:, :, :] = fwidth[:, 0:1, :]
fwidth = new_fwidth.reshape(-1, 3)
cphyc marked this conversation as resolved.
Show resolved Hide resolved
return fwidth

@property
def fcoords(self):
num_ghost_zones = self._num_ghost_zones
if num_ghost_zones == 0:
return super(RAMSESDomainSubset, self).fcoords

oh = self.oct_handler
cphyc marked this conversation as resolved.
Show resolved Hide resolved

indices = oh.fill_index(self.selector).reshape(-1, 8)
oinds, cinds = oh.fill_octcellindex_neighbours(self.selector)

oinds = oinds.reshape(-1, 64)
cinds = cinds.reshape(-1, 64)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm guessing... oct_index and cell_index ? Am I right ? if so, could you use those names instead ? if not, all the more reason to have better names !

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, I changed the names.


inds = indices[oinds, cinds]

fcoords = self.ds.arr(
oh.fcoords(self.selector)[inds].reshape(-1, 3),
'unitary')

return fcoords

def fill(self, fd, fields, selector, file_handler):
if self._num_ghost_zones == 0:
return self._fill_no_ghostzones(fd, fields, selector, file_handler)
else:
cphyc marked this conversation as resolved.
Show resolved Hide resolved
return self._fill_with_ghostzones(fd, fields, selector, file_handler, self._num_ghost_zones)

def retrieve_ghost_zones(self, ngz, fields, smoothed=False):
new_subset = RAMSESDomainSubset(self.base_region, self.domain, self.ds, num_ghost_zones=ngz, base_grid=self)

return new_subset

class RAMSESIndex(OctreeIndex):

def __init__(self, ds, dataset_type='ramses'):
Expand Down Expand Up @@ -260,7 +349,9 @@ def _identify_base_chunk(self, dobj):
base_region = getattr(dobj, "base_region", dobj)
if len(domains) > 1:
mylog.debug("Identified %s intersecting domains", len(domains))
subsets = [RAMSESDomainSubset(base_region, domain, self.dataset)
subsets = [RAMSESDomainSubset(
base_region, domain, self.dataset,
num_ghost_zones=dobj._num_ghost_zones)
for domain in domains]
dobj._chunk_info = subsets
dobj._current_chunk = list(self._chunk_all(dobj))[0]
Expand Down
81 changes: 46 additions & 35 deletions yt/frontends/ramses/io_utils.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def read_amr(FortranFile f, dict headers,
@cython.nonecheck(False)
cpdef read_offset(FortranFile f, INT64_t min_level, INT64_t domain_id, INT64_t nvar, dict headers):

cdef np.ndarray[np.int64_t, ndim=1] offset, level_count
cdef np.ndarray[np.int64_t, ndim=2] offset, level_count
cdef INT64_t ndim, twotondim, nlevelmax, n_levels, nboundary, ncpu, ncpu_and_bound
cdef INT64_t ilevel, icpu, skip_len
cdef INT32_t file_ilevel, file_ncache
Expand All @@ -101,12 +101,11 @@ cpdef read_offset(FortranFile f, INT64_t min_level, INT64_t domain_id, INT64_t n
skip_len = twotondim * nvar

# It goes: level, CPU, 8-variable (1 oct)
offset = np.zeros(n_levels, dtype=np.int64)
offset -= 1
level_count = np.zeros(n_levels, dtype=np.int64)
offset = np.full((ncpu_and_bound, n_levels), -1, dtype=np.int64)
level_count = np.zeros((ncpu_and_bound, n_levels), dtype=np.int64)

cdef np.int64_t[:] level_count_view = level_count
cdef np.int64_t[:] offset_view = offset
cdef np.int64_t[:,:] level_count_view = level_count
cdef np.int64_t[:,:] offset_view = offset

for ilevel in range(nlevelmax):
for icpu in range(ncpu_and_bound):
Expand All @@ -121,9 +120,9 @@ cpdef read_offset(FortranFile f, INT64_t min_level, INT64_t domain_id, INT64_t n
'from data (%s) is not coherent with the expected (%s)',
f.name, file_ilevel, ilevel)

if icpu + 1 == domain_id and ilevel >= min_level:
offset[ilevel - min_level] = f.tell()
level_count[ilevel - min_level] = <INT64_t> file_ncache
if ilevel >= min_level:
offset_view[icpu, ilevel - min_level] = f.tell()
level_count_view[icpu, ilevel - min_level] = <INT64_t> file_ncache
f.skip(skip_len)

return offset, level_count
Expand All @@ -133,45 +132,57 @@ cpdef read_offset(FortranFile f, INT64_t min_level, INT64_t domain_id, INT64_t n
@cython.cdivision(True)
@cython.nonecheck(False)
def fill_hydro(FortranFile f,
np.ndarray[np.int64_t, ndim=1] offsets,
np.ndarray[np.int64_t, ndim=1] level_count,
np.ndarray[np.int64_t, ndim=2] offsets,
np.ndarray[np.int64_t, ndim=2] level_count,
list cpu_enumerator,
np.ndarray[np.uint8_t, ndim=1] levels,
np.ndarray[np.uint8_t, ndim=1] cell_inds,
np.ndarray[np.int64_t, ndim=1] file_inds,
INT64_t ndim, list all_fields, list fields,
dict tr,
RAMSESOctreeContainer oct_handler):
cdef INT64_t ilevel, ifield, nfields, noffset
RAMSESOctreeContainer oct_handler,
np.ndarray[np.int32_t, ndim=1] domains=np.array([], dtype='int32')):
cdef INT64_t offset
cdef dict tmp
cdef str field
cdef INT64_t twotondim, i
cdef INT64_t twotondim
cdef int ilevel, icpu, ifield, nfields, nlevels, nc, ncpu_selected
cdef np.ndarray[np.uint8_t, ndim=1] mask

twotondim = 2**ndim
nfields = len(all_fields)
noffset = len(offsets)
ncpu = offsets.shape[0]
nlevels = offsets.shape[1]
ncpu_selected = len(cpu_enumerator)

mask = np.array([(field in fields) for field in all_fields], dtype=np.uint8)

# Loop over levels
for ilevel in range(noffset):
offset = offsets[ilevel]
if offset == -1:
continue
f.seek(offset)
nc = level_count[ilevel]
tmp = {}
# Initalize temporary data container for io
for field in all_fields:
tmp[field] = np.empty((nc, twotondim), dtype="float64")

for i in range(twotondim):
# Read the selected fields
for ifield in range(nfields):
if not mask[ifield]:
f.skip()
else:
tmp[all_fields[ifield]][:, i] = f.read_vector('d') # i-th cell

oct_handler.fill_level(ilevel, levels, cell_inds, file_inds, tr, tmp)
for ilevel in range(nlevels):
# Loop over cpu domains
for icpu in cpu_enumerator:
nc = level_count[icpu, ilevel]
if nc == 0:
continue
offset = offsets[icpu, ilevel]
if offset == -1:
continue
f.seek(offset)
tmp = {}
# Initalize temporary data container for io
for field in all_fields:
tmp[field] = np.empty((nc, twotondim), dtype="float64", order='F')
cphyc marked this conversation as resolved.
Show resolved Hide resolved

for i in range(twotondim):
# Read the selected fields
for ifield in range(nfields):
if not mask[ifield]:
f.skip()
else:
tmp[all_fields[ifield]][:, i] = f.read_vector('d') # i-th cell
if ncpu_selected > 1:
oct_handler.fill_level_with_domain(
ilevel, levels, cell_inds, file_inds, domains, tr, tmp, domain=icpu+1)
else:
oct_handler.fill_level(
ilevel, levels, cell_inds, file_inds, tr, tmp)
Loading