From 2b0f162d1390adbec9013a3f3fe0aeec2b929b5a Mon Sep 17 00:00:00 2001 From: Jean-Matthieu Etancelin <jean-matthieu.etancelin@univ-pau.fr> Date: Wed, 27 Jun 2018 15:10:07 +0200 Subject: [PATCH] Add python backend for enstrophy operator --- .../device/opencl/operator/enstrophy.py | 15 +++----- .../backend/host/python/operator/enstrophy.py | 37 ++++++++++++++++++ hysop/operator/base/enstrophy.py | 31 +++++++-------- hysop/operator/enstrophy.py | 38 +++++++++---------- 4 files changed, 78 insertions(+), 43 deletions(-) create mode 100644 hysop/backend/host/python/operator/enstrophy.py diff --git a/hysop/backend/device/opencl/operator/enstrophy.py b/hysop/backend/device/opencl/operator/enstrophy.py index 0a8f8ec3c..766bdb3c5 100644 --- a/hysop/backend/device/opencl/operator/enstrophy.py +++ b/hysop/backend/device/opencl/operator/enstrophy.py @@ -1,4 +1,3 @@ - from hysop.deps import sm from hysop.constants import DirectionLabels from hysop.backend.device.opencl.opencl_array_backend import OpenClArrayBackend @@ -23,13 +22,13 @@ class OpenClEnstrophy(EnstrophyBase, OpenClSymbolic): rho = self.rho rhos = (rho.s if (rho is not None) else sm.Integer(1)) - + Ws = self.vorticity.s() WdotW = self.WdotW.s() expr = Assignment(WdotW, rhos*npw.dot(Ws, Ws)) self.require_symbolic_kernel('WdotW', expr) - + @debug def get_field_requirements(self): # force 0 ghosts for the reduction (pyopencl reduction kernel) @@ -38,21 +37,19 @@ class OpenClEnstrophy(EnstrophyBase, OpenClSymbolic): if field is self.WdotW: req.max_ghosts = (0,)*self.WdotW.dim return requirements - + @debug def discretize(self): super(OpenClEnstrophy, self).discretize() assert (self.dWdotW.ghosts == 0).all() - self.coeff = npw.prod(self.dWdotW.space_step) - self.coeff /= (self.rho_0 * npw.prod(self.dWdotW.domain.length)) - + @debug def setup(self, work): super(OpenClEnstrophy, self).setup(work) (self.WdotW_kernel, self.WdotW_update_parameters) = self.symbolic_kernels['WdotW'] - self.sum_kernel = self.dWdotW.backend.nansum(a=self.dWdotW[0], + self.sum_kernel = self.dWdotW.backend.nansum(a=self.dWdotW[0], build_kernel_launcher=True, async=True) - + @op_apply def apply(self, **kwds): queue = self.cl_env.default_queue diff --git a/hysop/backend/host/python/operator/enstrophy.py b/hysop/backend/host/python/operator/enstrophy.py new file mode 100644 index 000000000..3ec1080dd --- /dev/null +++ b/hysop/backend/host/python/operator/enstrophy.py @@ -0,0 +1,37 @@ +""" +@file enstrophy.py +Enstrophy solver python backend. +""" +from hysop.tools.decorators import debug +from hysop.core.graph.graph import op_apply +from hysop.operator.base.enstrophy import EnstrophyBase +from hysop.backend.host.host_operator import HostOperator +from hysop.tools.numpywrappers import npw + + +class PythonEnstrophy(EnstrophyBase, HostOperator): + """Compute enstrophy of the given vorticity field.""" + @debug + def __init__(self, **kwds): + super(PythonEnstrophy, self).__init__(**kwds) + assert self.mpi_params.size == 1 + + @op_apply + def apply(self, **kwds): + print self.dWin.data[0].shape, self.dWdotW.data[0].shape + print len(self.dWin.data), len(self.dWdotW.data) + + # Compute W dot W + wd = self.dWin + wdotw = self.dWdotW[0] + nbc = wd.nb_components + ic = wd.compute_slices + wdotw[...] = 0. + for i in xrange(nbc): + wdotw[...] += (wd[i][ic] ** 2) + + # Compute enstrophy + local_enstrophy = self.coeff * npw.real_sum(wdotw) + # TODO reduce over all mpi process + + self.enstrophy.value = local_enstrophy diff --git a/hysop/operator/base/enstrophy.py b/hysop/operator/base/enstrophy.py index ea1e81478..6f46e2750 100644 --- a/hysop/operator/base/enstrophy.py +++ b/hysop/operator/base/enstrophy.py @@ -1,10 +1,9 @@ - - from abc import ABCMeta from hysop.tools.types import check_instance, to_tuple, first_not_None from hysop.tools.decorators import debug from hysop.fields.continuous_field import Field +from hysop.tools.numpywrappers import npw from hysop.core.memory.memory_request import MemoryRequest from hysop.topology.cartesian_descriptor import CartesianTopologyDescriptors @@ -22,13 +21,13 @@ class EnstrophyBase(object): variables, name=None, pretty_name=None, **kwds): """ Initialize a enstrophy operator operating on CartesianTopologyDescriptors. - + vorticity: Field Input continuous vorticity field. enstrophy: ScalarParameter Enstrophy scalar output parameter. rho: Field, optional - Input continuous density field, if not given, + Input continuous density field, if not given, defaults to 1.0 on the whole domain. rho_0: float, optional Reference density, defaults to 1.0. @@ -36,40 +35,40 @@ class EnstrophyBase(object): Output continuous field, will contain W.W (term before integration). If WdotW is given, WdotW will contain W.W else this will be a temporary field only usable during this operator's apply method. - Should have nb_components=1 and the same domain and discretization + Should have nb_components=1 and the same domain and discretization as the vorticity. variables: dict dictionary of fields as keys and topologies as values. kwds: - Keywords arguments that will be passed towards implementation + Keywords arguments that will be passed towards implementation poisson operator __init__. """ - + check_instance(vorticity, Field) check_instance(enstrophy, ScalarParameter) check_instance(variables, dict, keys=Field, values=CartesianTopologyDescriptors) check_instance(WdotW, Field, allow_none=True) check_instance(rho, Field, allow_none=True) check_instance(rho_0, float) - + W = vorticity.pretty_name.decode('utf-8') wdotw = u'{}\u22c5{}'.format(W,W) if (WdotW is None): assert (vorticity in variables), variables WdotW = vorticity.tmp_like(name='WdotW', pretty_name=wdotw, nb_components=1) variables[WdotW] = variables[vorticity] - + input_fields = { vorticity: variables[vorticity] } output_fields = { WdotW: variables[WdotW] } output_params = { enstrophy.name: enstrophy } if (rho is not None): input_fields[rho] = variables[rho] - + default_name = 'enstrophy' default_pname = u'\u222b{}'.format(wdotw).encode('utf-8') - + pretty_name = first_not_None(pretty_name, name, default_pname) name = first_not_None(name, default_name) @@ -78,11 +77,11 @@ class EnstrophyBase(object): self.rho_0 = rho_0 self.WdotW = WdotW self.enstrophy = enstrophy - - super(EnstrophyBase, self).__init__(input_fields=input_fields, - output_fields=output_fields, output_params=output_params, + + super(EnstrophyBase, self).__init__(input_fields=input_fields, + output_fields=output_fields, output_params=output_params, name=name, pretty_name=pretty_name, **kwds) - + @debug def discretize(self): if self.discretized: @@ -91,3 +90,5 @@ class EnstrophyBase(object): self.dWin = self.input_discrete_fields[self.vorticity] self.dWdotW = self.output_discrete_fields[self.WdotW] + self.coeff = npw.prod(self.dWdotW.space_step) + self.coeff /= (self.rho_0 * npw.prod(self.dWdotW.domain.length)) diff --git a/hysop/operator/enstrophy.py b/hysop/operator/enstrophy.py index a8637dcd4..09b2a3276 100644 --- a/hysop/operator/enstrophy.py +++ b/hysop/operator/enstrophy.py @@ -1,5 +1,3 @@ - - """ @file enstrophy.py Enstrophy solver frontend. @@ -17,37 +15,40 @@ from hysop.parameters.scalar_parameter import ScalarParameter class Enstrophy(ComputationalGraphNodeFrontend): """ Interface computing enstrophy. - Available implementations are: - *OPENCL (gpu based implementation) + Available implementations are: + *OPENCL (gpu based implementation) (default) + *PYTHON """ - + @classmethod def implementations(cls): from hysop.backend.device.opencl.operator.enstrophy import OpenClEnstrophy + from hysop.backend.host.python.operator.enstrophy import PythonEnstrophy implementations = { - Implementation.OPENCL: OpenClEnstrophy + Implementation.OPENCL: OpenClEnstrophy, + Implementation.PYTHON: PythonEnstrophy } return implementations - + @classmethod def default_implementation(cls): return Implementation.OPENCL - + @debug - def __init__(self, vorticity, enstrophy, variables, - rho=None, rho_0=1.0, WdotW=None, + def __init__(self, vorticity, enstrophy, variables, + rho=None, rho_0=1.0, WdotW=None, implementation=None, base_kwds=None, **kwds): """ Initialize a Enstrophy operator frontend. - Enstrophy is the scaled volume average of rho*(W.W) on the domain where . represents + Enstrophy is the scaled volume average of rho*(W.W) on the domain where . represents the vector dot product). in: W (vorticity field) rho (density field, optional, defaults to 1.0 everywhere) out: E = 1.0/(2*V*rho_0) * integral(rho*(W.W)) => enstrophy (scalar parameter) where V is the domain volume, rho_0 the reference density. - + Parameters ---------- vorticity: Field @@ -55,7 +56,7 @@ class Enstrophy(ComputationalGraphNodeFrontend): enstrophy: ScalarParameter Enstrophy scalar output parameter. rho: Field, optional - Input continuous density field, if not given, + Input continuous density field, if not given, defaults to 1.0 on the whole domain. rho_0: float, optional Reference density, defaults to 1.0. @@ -73,12 +74,12 @@ class Enstrophy(ComputationalGraphNodeFrontend): Base class keywords arguments. If None, an empty dict will be passed. kwds: - Extra keywords arguments that will be passed towards implementation + Extra keywords arguments that will be passed towards implementation enstrophy operator __init__. Notes ----- - An Enstrophy operator implementation should at least support + An Enstrophy operator implementation should at least support the hysop.operator.base.enstrophy.EnstrophyBase interface. """ base_kwds = base_kwds or dict() @@ -90,9 +91,8 @@ class Enstrophy(ComputationalGraphNodeFrontend): check_instance(WdotW, Field, allow_none=True) check_instance(rho, Field, allow_none=True) check_instance(rho_0, float) - - super(Enstrophy, self).__init__(vorticity=vorticity, rho=rho, + + super(Enstrophy, self).__init__(vorticity=vorticity, rho=rho, enstrophy=enstrophy, WdotW=WdotW, rho_0=rho_0, - variables=variables, base_kwds=base_kwds, + variables=variables, base_kwds=base_kwds, implementation=implementation, **kwds) - -- GitLab