Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
6466cf1
list_of_pset_array_trials - initial addenda for list-of-particles ver…
CKehl Jul 7, 2020
9f52d80
list_of_pset_array_trials - wrapped up list-of-array adaptations in t…
CKehl Jul 8, 2020
064cbf0
list_of_pset_array_trials - adapted the kernel to work with list-of-a…
CKehl Jul 8, 2020
46f97d0
list_of_pset_array_trials - adapted the particle file to work with th…
CKehl Jul 8, 2020
9a41211
list_of_pset_array_trials - last adaptations before testing in order …
CKehl Jul 8, 2020
c653516
list_of_pset_array_trials - fixed minor issues due to testing. Now ne…
CKehl Jul 8, 2020
9997a98
list_of_pset_array_trials - transformed PID mapping from dict into list
CKehl Jul 8, 2020
73ebfac
list_of_pset_array_trials - atted __getitem__(self, key) func to Part…
CKehl Jul 8, 2020
2107f8d
list_of_pset_array_trials - fixing address translation 1-array index …
CKehl Jul 9, 2020
518753e
list_of_pset_array_trials - fixed errors emerging from tests
CKehl Jul 14, 2020
49f5055
list_of_pset_array_trials - fixing linter errors
CKehl Jul 14, 2020
60c40f3
list_of_pset_array_trials - added benchmark refactoring. tested and w…
CKehl Jul 16, 2020
3dafd24
list_of_pset_array_trials - rebase to benchmarking branch rev 54e4c18
CKehl Jul 20, 2020
29574a4
list_of_pset_array_trials - fixed issues in file writing
CKehl Dec 1, 2020
f418419
origin/list_of_pset_array_trials - added a version where the 1st-leve…
CKehl Dec 9, 2020
7a626a3
list_of_pset_array_trials - finalised the correct memory consumption …
CKehl Dec 9, 2020
2f165b6
list_of_pset_array_trials - initial addenda for list-of-particles ver…
CKehl Jul 7, 2020
cdf4a52
list_of_pset_array_trials - wrapped up list-of-array adaptations in t…
CKehl Jul 8, 2020
084c6e2
list_of_pset_array_trials - fixing linter errors
CKehl Jul 14, 2020
d16560b
list_of_pset_array_trials - added benchmark refactoring. tested and w…
CKehl Jul 16, 2020
2bb9ad5
list_of_pset_array_trials - rebase to benchmarking branch rev 54e4c18
CKehl Jul 20, 2020
77d057b
list_of_pset_array_trials - finalised the correct memory consumption …
CKehl Dec 9, 2020
b78fcd2
list_of_pset_array_trials - initial addenda for list-of-particles ver…
CKehl Jul 7, 2020
44985e7
list_of_pset_array_trials - wrapped up list-of-array adaptations in t…
CKehl Jul 8, 2020
6c04661
list_of_pset_array_trials - fixing linter errors
CKehl Jul 14, 2020
84b05f1
list_of_pset_array_trials - added benchmark refactoring. tested and w…
CKehl Jul 16, 2020
9b3a1c3
list_of_pset_array_trials - rebase to benchmarking branch rev 54e4c18
CKehl Jul 20, 2020
60ee34c
list_of_pset_array_trials - initial addenda for list-of-particles ver…
CKehl Jul 7, 2020
c5ea274
list_of_pset_array_trials - adapted the particle file to work with th…
CKehl Jul 8, 2020
722d44c
list_of_pset_array_trials - fixing linter errors
CKehl Jul 14, 2020
081f888
list_of_pset_array_trials - added benchmark refactoring. tested and w…
CKehl Jul 16, 2020
8601514
list_of_pset_array_trials - rebase to benchmarking branch rev 54e4c18
CKehl Jul 20, 2020
d98d9fc
list_of_pset_array_trials - initial addenda for list-of-particles ver…
CKehl Jul 7, 2020
791f067
list_of_pset_array_trials - wrapped up list-of-array adaptations in t…
CKehl Jul 8, 2020
e71e466
list_of_pset_array_trials - fixing linter errors
CKehl Jul 14, 2020
14827a3
list_of_pset_array_trials - added benchmark refactoring. tested and w…
CKehl Jul 16, 2020
afacbd3
list_of_pset_array_trials - rebase to benchmarking branch rev 54e4c18
CKehl Jul 20, 2020
e7dd4f6
list_of_pset_array_trials - initial addenda for list-of-particles ver…
CKehl Jul 7, 2020
2080637
list_of_pset_array_trials - wrapped up list-of-array adaptations in t…
CKehl Jul 8, 2020
c7005df
list_of_pset_array_trials - adapted the kernel to work with list-of-a…
CKehl Jul 8, 2020
fee95d1
list_of_pset_array_trials - adapted the particle file to work with th…
CKehl Jul 8, 2020
4d61245
list_of_pset_array_trials - fixed errors emerging from tests
CKehl Jul 14, 2020
0fe9417
list_of_pset_array_trials - fixing linter errors
CKehl Jul 14, 2020
16a8903
list_of_pset_array_trials - added benchmark refactoring. tested and w…
CKehl Jul 16, 2020
e25e870
list_of_pset_array_trials - rebase to benchmarking branch rev 54e4c18
CKehl Jul 20, 2020
135986a
list_of_pset_array_trials - initial addenda for list-of-particles ver…
CKehl Jul 7, 2020
e0f995d
list_of_pset_array_trials - atted __getitem__(self, key) func to Part…
CKehl Jul 8, 2020
9595993
list_of_pset_array_trials - fixed errors emerging from tests
CKehl Jul 14, 2020
613bda5
list_of_pset_array_trials - fixing linter errors
CKehl Jul 14, 2020
11f8027
list_of_pset_array_trials - added benchmark refactoring. tested and w…
CKehl Jul 16, 2020
8737b2f
list_of_pset_array_trials - rebase to benchmarking branch rev 54e4c18
CKehl Jul 20, 2020
f743a8a
list_of_pset_array_trials - initial addenda for list-of-particles ver…
CKehl Jul 7, 2020
75de5e4
list_of_pset_array_trials - fixing linter errors
CKehl Jul 14, 2020
1981d44
list_of_pset_array_trials - added benchmark refactoring. tested and w…
CKehl Jul 16, 2020
eb329ff
list_of_pset_array_trials - rebase to benchmarking branch rev 54e4c18
CKehl Jul 20, 2020
ae1e349
list_of_pset_array_trials - changed the branch names in the performan…
CKehl Feb 4, 2021
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
220 changes: 124 additions & 96 deletions parcels/kernel.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,9 +219,13 @@ def load_lib(self):

def execute_jit(self, pset, endtime, dt):
"""Invokes JIT engine to perform the core update loop"""
if len(pset.particles) > 0:
assert pset.fieldset.gridset.size == len(pset.particles[0].xi), \
if len(pset.particles_a) > 0 and pset.particles_a[0].shape[0]:
assert pset.fieldset.gridset.size == len(pset.particles_a[0][0].xi), \
'FieldSet has different amount of grids than Particle.xi. Have you added Fields after creating the ParticleSet?'

# if len(pset.particles) > 0:
# assert pset.fieldset.gridset.size == len(pset.particles[0].xi), \
# 'FieldSet has different amount of grids than Particle.xi. Have you added Fields after creating the ParticleSet?'
for g in pset.fieldset.gridset.grids:
g.cstruct = None # This force to point newly the grids from Python to C
# Make a copy of the transposed array to enforce
Expand Down Expand Up @@ -250,11 +254,18 @@ def execute_jit(self, pset, endtime, dt):

fargs = [byref(f.ctypes_struct) for f in self.field_args.values()]
fargs += [c_double(f) for f in self.const_args.values()]
particle_data = pset._particle_data.ctypes.data_as(c_void_p)
self._function(c_int(len(pset)), particle_data,
c_double(endtime),
c_double(dt),
*fargs)

for subfield_c in pset.particles_c:
Copy link
Member

Choose a reason for hiding this comment

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

It's a bit confusing you call this subfield, because a Field is a specific object in Parcels, and I don't think that these subfields have anything to do with Fields

particle_data = subfield_c.ctypes.data_as(c_void_p)
self._function(c_int(subfield_c.shape[0]), particle_data,
c_double(endtime), c_double(dt),
*fargs)

# particle_data = pset._particle_data.ctypes.data_as(c_void_p)
# self._function(c_int(len(pset)), particle_data,
# c_double(endtime),
# c_double(dt),
# *fargs)

def execute_python(self, pset, endtime, dt):
"""Performs the core update loop via Python"""
Expand All @@ -268,104 +279,122 @@ def execute_python(self, pset, endtime, dt):
continue
f.data = np.array(f.data)

for p in pset.particles:
ptype = p.getPType()
# Don't execute particles that aren't started yet
sign_end_part = np.sign(endtime - p.time)
# for p in pset.particles:
for subfield in pset.particles_a:
for p in subfield:
ptype = p.getPType()
# Don't execute particles that aren't started yet
sign_end_part = np.sign(endtime - p.time)

dt_pos = min(abs(p.dt), abs(endtime - p.time))
dt_pos = min(abs(p.dt), abs(endtime - p.time))

# ==== numerically stable; also making sure that continuously-recovered particles do end successfully,
# as they fulfil the condition here on entering at the final calculation here. ==== #
if ((sign_end_part != sign_dt) or np.isclose(dt_pos, 0)) and not np.isclose(dt, 0):
if abs(p.time) >= abs(endtime):
p.state = ErrorCode.Success
continue
# ==== numerically stable; also making sure that continuously-recovered particles do end successfully,
# as they fulfil the condition here on entering at the final calculation here. ==== #
if ((sign_end_part != sign_dt) or np.isclose(dt_pos, 0)) and not np.isclose(dt, 0):
if abs(p.time) >= abs(endtime):
p.state = ErrorCode.Success
continue

while p.state in [ErrorCode.Evaluate, ErrorCode.Repeat] or np.isclose(dt, 0):

for var in ptype.variables:
p_var_back[var.name] = getattr(p, var.name)
try:
pdt_prekernels = sign_dt * dt_pos
p.dt = pdt_prekernels
state_prev = p.state
res = self.pyfunc(p, pset.fieldset, p.time)
if res is None:
res = ErrorCode.Success

if res is ErrorCode.Success and p.state != state_prev:
res = p.state

if res == ErrorCode.Success and not np.isclose(p.dt, pdt_prekernels):
res = ErrorCode.Repeat

except FieldOutOfBoundError as fse_xy:
res = ErrorCode.ErrorOutOfBounds
p.exception = fse_xy
except FieldOutOfBoundSurfaceError as fse_z:
res = ErrorCode.ErrorThroughSurface
p.exception = fse_z
except TimeExtrapolationError as fse_t:
res = ErrorCode.ErrorTimeExtrapolation
p.exception = fse_t
except Exception as e:
res = ErrorCode.Error
p.exception = e

# Handle particle time and time loop
if res in [ErrorCode.Success, ErrorCode.Delete]:
# Update time and repeat
p.time += p.dt
p.update_next_dt()
dt_pos = min(abs(p.dt), abs(endtime - p.time))

sign_end_part = np.sign(endtime - p.time)
if res != ErrorCode.Delete and not np.isclose(dt_pos, 0) and (sign_end_part == sign_dt):
res = ErrorCode.Evaluate
if sign_end_part != sign_dt:
dt_pos = 0

p.state = res
if np.isclose(dt, 0):
break
else:
p.state = res
# Try again without time update
for var in ptype.variables:
if var.name not in ['dt', 'state']:
setattr(p, var.name, p_var_back[var.name])
dt_pos = min(abs(p.dt), abs(endtime - p.time))
while p.state in [ErrorCode.Evaluate, ErrorCode.Repeat] or np.isclose(dt, 0):

sign_end_part = np.sign(endtime - p.time)
if sign_end_part != sign_dt:
dt_pos = 0
break
for var in ptype.variables:
p_var_back[var.name] = getattr(p, var.name)
try:
pdt_prekernels = sign_dt * dt_pos
p.dt = pdt_prekernels
state_prev = p.state
res = self.pyfunc(p, pset.fieldset, p.time)
if res is None:
res = ErrorCode.Success

if res is ErrorCode.Success and p.state != state_prev:
res = p.state

if res == ErrorCode.Success and not np.isclose(p.dt, pdt_prekernels):
res = ErrorCode.Repeat

except FieldOutOfBoundError as fse_xy:
res = ErrorCode.ErrorOutOfBounds
p.exception = fse_xy
except FieldOutOfBoundSurfaceError as fse_z:
res = ErrorCode.ErrorThroughSurface
p.exception = fse_z
except TimeExtrapolationError as fse_t:
res = ErrorCode.ErrorTimeExtrapolation
p.exception = fse_t
except Exception as e:
res = ErrorCode.Error
p.exception = e

# Handle particle time and time loop
if res in [ErrorCode.Success, ErrorCode.Delete]:
# Update time and repeat
p.time += p.dt
p.update_next_dt()
dt_pos = min(abs(p.dt), abs(endtime - p.time))

sign_end_part = np.sign(endtime - p.time)
if res != ErrorCode.Delete and not np.isclose(dt_pos, 0) and (sign_end_part == sign_dt):
res = ErrorCode.Evaluate
if sign_end_part != sign_dt:
dt_pos = 0

p.state = res
if np.isclose(dt, 0):
break
else:
p.state = res
# Try again without time update
for var in ptype.variables:
if var.name not in ['dt', 'state']:
setattr(p, var.name, p_var_back[var.name])
dt_pos = min(abs(p.dt), abs(endtime - p.time))

sign_end_part = np.sign(endtime - p.time)
if sign_end_part != sign_dt:
dt_pos = 0
break

def remove_deleted(self, pset, output_file, endtime):
"""Utility to remove all particles that signalled deletion"""
indices = [i for i, p in enumerate(pset.particles)
if p.state in [ErrorCode.Delete]]
if len(indices) > 0 and output_file is not None:
output_file.write(pset[indices], endtime, deleted_only=True)
pset.remove(indices)
"""Utility to remove all particles that signalled deletion"""
indices = []
dparticles = []
for subfield in pset.particles_a:
# del_items = [(i, p) for i, p in enumerate(subfield) if p.state in [ErrorCode.Delete]] # we could unzip that, but in Python <3.6, more than 255 elem would make it crash
local_indices = []
local_particles = []
for i, p in enumerate(subfield):
if p.state == ErrorCode.Delete:
local_indices.append(i)
local_particles.append(p)
if len(local_particles) > 0:
local_particles = np.array(local_particles)
local_indices = np.array(local_indices)
else:
local_particles = None
local_indices = None
indices.append(local_indices)
dparticles.append(local_particles)
# ==== do / fix ParticleFile TODO ==== #
if output_file is not None:
output_file.write(dparticles, endtime, deleted_only=True) # => individual entries being None -> handled in ParticleFile
# indices = [i for i, p in enumerate(pset.particles) if p.state in [ErrorCode.Delete]]
# if len(indices) > 0 and output_file is not None:
# output_file.write(pset[indices], endtime, deleted_only=True)
pset.remove(indices)

def execute(self, pset, endtime, dt, recovery=None, output_file=None, execute_once=False):
"""Execute this Kernel over a ParticleSet for several timesteps"""
for p in pset.particles:
p.reset_state()
for subfield in pset.particles_a:
for p in subfield:
p.reset_state()

# for p in pset.particles:
# p.reset_state()

if abs(dt) < 1e-6 and not execute_once:
logger.warning_once("'dt' is too small, causing numerical accuracy limit problems. Please chose a higher 'dt' and rather scale the 'time' axis of the field accordingly. (related issue #762)")

# def remove_deleted(pset):
# """Utility to remove all particles that signalled deletion"""
# indices = [i for i, p in enumerate(pset.particles)
# if p.state in [ErrorCode.Delete]]
# if len(indices) > 0 and output_file is not None:
# output_file.write(pset[indices], endtime, deleted_only=True)
# pset.remove(indices)

if recovery is None:
recovery = {}
elif ErrorCode.ErrorOutOfBounds in recovery and ErrorCode.ErrorThroughSurface not in recovery:
Expand All @@ -386,8 +415,8 @@ def execute(self, pset, endtime, dt, recovery=None, output_file=None, execute_on
# Remove all particles that signalled deletion
self.remove_deleted(pset, output_file=output_file, endtime=endtime)

# Identify particles that threw errors
error_particles = [p for p in pset.particles if p.state not in [ErrorCode.Success, ErrorCode.Evaluate]]
# == Identify particles that threw errors == #
error_particles = [p for subfield in pset.particles_a for p in subfield if p.state not in [ErrorCode.Success, ErrorCode.Evaluate]]

while len(error_particles) > 0:
# Apply recovery kernel
Expand All @@ -397,7 +426,6 @@ def execute(self, pset, endtime, dt, recovery=None, output_file=None, execute_on
if p.state == ErrorCode.Repeat:
p.reset_state()
elif p.state == ErrorCode.Delete:
# p.delete()
pass
elif p.state in recovery_map:
recovery_kernel = recovery_map[p.state]
Expand All @@ -419,7 +447,7 @@ def execute(self, pset, endtime, dt, recovery=None, output_file=None, execute_on
else:
self.execute_python(pset, endtime, dt)

error_particles = [p for p in pset.particles if p.state not in [ErrorCode.Success, ErrorCode.Evaluate]]
error_particles = [p for subfield in pset.particles_a for p in subfield if p.state not in [ErrorCode.Success, ErrorCode.Evaluate]]

def merge(self, kernel):
funcname = self.funcname + kernel.funcname
Expand Down
Loading