Skip to content

Commit 553e1cb

Browse files
committed
support empty groups in reductions
1 parent 05ecbc9 commit 553e1cb

1 file changed

Lines changed: 42 additions & 16 deletions

File tree

grudge/reductions.py

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ def norm(dcoll: DiscretizationCollection, vec, p, dd=None) -> Scalar:
108108
actx.np.conjugate(vec)
109109
* _apply_mass_operator(dcoll, dd, dd, vec))))
110110
elif p == np.inf:
111-
return nodal_max(dcoll, dd, actx.np.abs(vec))
111+
return nodal_max(dcoll, dd, actx.np.abs(vec), init=0.)
112112
else:
113113
raise ValueError("unsupported norm order")
114114

@@ -153,95 +153,121 @@ def nodal_sum_loc(dcoll: DiscretizationCollection, dd, vec) -> Scalar:
153153

154154
actx = vec.array_context
155155

156-
return sum([actx.np.sum(grp_ary) for grp_ary in vec])
156+
return sum([
157+
actx.np.sum(grp_ary) if grp_ary.size > 0 else actx.from_numpy(np.array(0.))
158+
for grp_ary in vec])
157159

158160

159-
def nodal_min(dcoll: DiscretizationCollection, dd, vec) -> Scalar:
161+
def nodal_min(dcoll: DiscretizationCollection, dd, vec, *, init=None) -> Scalar:
160162
r"""Return the nodal minimum of a vector of degrees of freedom *vec*.
161163
162164
:arg dd: a :class:`~grudge.dof_desc.DOFDesc`, or a value
163165
convertible to one.
164166
:arg vec: a :class:`~meshmode.dof_array.DOFArray` or an
165167
:class:`~arraycontext.container.ArrayContainer` of them.
168+
:arg init: an optional initial value. Defaults to `numpy.inf`.
166169
:returns: a device scalar denoting the nodal minimum.
167170
"""
168171
comm = dcoll.mpi_communicator
169172
if comm is None:
170-
return nodal_min_loc(dcoll, dd, vec)
173+
return nodal_min_loc(dcoll, dd, vec, init=init)
171174

172175
# NOTE: Do not move, we do not want to import mpi4py in single-rank computations
173176
from mpi4py import MPI
174177
actx = vec.array_context
175178

176179
return actx.from_numpy(
177-
comm.allreduce(actx.to_numpy(nodal_min_loc(dcoll, dd, vec)), op=MPI.MIN))
180+
comm.allreduce(
181+
actx.to_numpy(nodal_min_loc(dcoll, dd, vec, init=init)),
182+
op=MPI.MIN))
178183

179184

180-
def nodal_min_loc(dcoll: DiscretizationCollection, dd, vec) -> Scalar:
185+
def nodal_min_loc(dcoll: DiscretizationCollection, dd, vec, *, init=None) -> Scalar:
181186
r"""Return the rank-local nodal minimum of a vector of degrees
182187
of freedom *vec*.
183188
184189
:arg dd: a :class:`~grudge.dof_desc.DOFDesc`, or a value
185190
convertible to one.
186191
:arg vec: a :class:`~meshmode.dof_array.DOFArray` or an
187192
:class:`~arraycontext.container.ArrayContainer` of them.
193+
:arg init: an optional initial value. Defaults to `numpy.inf`.
188194
:returns: a scalar denoting the rank-local nodal minimum.
189195
"""
190196
if not isinstance(vec, DOFArray):
191197
return min(
192-
nodal_min_loc(dcoll, dd, comp)
198+
nodal_min_loc(dcoll, dd, comp, init=init)
193199
for _, comp in serialize_container(vec)
194200
)
195201

196202
actx = vec.array_context
197203

204+
if init is None:
205+
init = np.inf
206+
207+
if np.isscalar(init):
208+
init = actx.from_numpy(np.array(init))
209+
198210
return reduce(
199-
lambda acc, grp_ary: actx.np.minimum(acc, actx.np.min(grp_ary)),
200-
vec, actx.from_numpy(np.array(np.inf)))
211+
lambda acc, grp_ary: actx.np.minimum(
212+
acc,
213+
actx.np.min(grp_ary) if grp_ary.size > 0 else init),
214+
vec, init)
201215

202216

203-
def nodal_max(dcoll: DiscretizationCollection, dd, vec) -> Scalar:
217+
def nodal_max(dcoll: DiscretizationCollection, dd, vec, *, init=None) -> Scalar:
204218
r"""Return the nodal maximum of a vector of degrees of freedom *vec*.
205219
206220
:arg dd: a :class:`~grudge.dof_desc.DOFDesc`, or a value
207221
convertible to one.
208222
:arg vec: a :class:`~meshmode.dof_array.DOFArray` or an
209223
:class:`~arraycontext.container.ArrayContainer` of them.
224+
:arg init: an optional initial value. Defaults to `-numpy.inf`.
210225
:returns: a device scalar denoting the nodal maximum.
211226
"""
212227
comm = dcoll.mpi_communicator
213228
if comm is None:
214-
return nodal_max_loc(dcoll, dd, vec)
229+
return nodal_max_loc(dcoll, dd, vec, init=init)
215230

216231
# NOTE: Do not move, we do not want to import mpi4py in single-rank computations
217232
from mpi4py import MPI
218233
actx = vec.array_context
219234

220235
return actx.from_numpy(
221-
comm.allreduce(actx.to_numpy(nodal_max_loc(dcoll, dd, vec)), op=MPI.MAX))
236+
comm.allreduce(
237+
actx.to_numpy(nodal_max_loc(dcoll, dd, vec, init=init)),
238+
op=MPI.MAX))
222239

223240

224-
def nodal_max_loc(dcoll: DiscretizationCollection, dd, vec) -> Scalar:
241+
def nodal_max_loc(dcoll: DiscretizationCollection, dd, vec, *, init=None) -> Scalar:
225242
r"""Return the rank-local nodal maximum of a vector of degrees
226243
of freedom *vec*.
227244
228245
:arg dd: a :class:`~grudge.dof_desc.DOFDesc`, or a value
229246
convertible to one.
230247
:arg vec: a :class:`~meshmode.dof_array.DOFArray` or an
231248
:class:`~arraycontext.container.ArrayContainer`.
249+
:arg init: an optional initial value. Defaults to `-numpy.inf`.
232250
:returns: a scalar denoting the rank-local nodal maximum.
233251
"""
234252
if not isinstance(vec, DOFArray):
235253
return max(
236-
nodal_max_loc(dcoll, dd, comp)
254+
nodal_max_loc(dcoll, dd, comp, init=init)
237255
for _, comp in serialize_container(vec)
238256
)
239257

240258
actx = vec.array_context
241259

260+
if init is None:
261+
init = -np.inf
262+
263+
if np.isscalar(init):
264+
init = actx.from_numpy(np.array(init))
265+
242266
return reduce(
243-
lambda acc, grp_ary: actx.np.maximum(acc, actx.np.max(grp_ary)),
244-
vec, actx.from_numpy(np.array(-np.inf)))
267+
lambda acc, grp_ary: actx.np.maximum(
268+
acc,
269+
actx.np.max(grp_ary) if grp_ary.size > 0 else init),
270+
vec, init)
245271

246272

247273
def integral(dcoll: DiscretizationCollection, dd, vec) -> Scalar:

0 commit comments

Comments
 (0)