From 36378742745d6e6b947ffefc99de9816e476174c Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Keck <Jean-Baptiste.Keck@imag.fr> Date: Tue, 11 Dec 2018 17:12:54 +0100 Subject: [PATCH] ext force --- examples/sediment_deposit/sediment_deposit.py | 11 +- .../codegen/kernels/directional_advection.py | 19 ++- .../autotunable_kernels/advection_dir.py | 3 - hysop/operator/adapt_timestep.py | 2 +- hysop/operator/base/external_force.py | 157 ++++++++++++++++++ hysop/operator/base/spectral_operator.py | 8 +- 6 files changed, 185 insertions(+), 15 deletions(-) create mode 100644 hysop/operator/base/external_force.py diff --git a/examples/sediment_deposit/sediment_deposit.py b/examples/sediment_deposit/sediment_deposit.py index 82c66c9a3..140251f5a 100644 --- a/examples/sediment_deposit/sediment_deposit.py +++ b/examples/sediment_deposit/sediment_deposit.py @@ -3,10 +3,10 @@ import scipy as sp import sympy as sm import numba as nb -TANK_RATIO = 1 +TANK_RATIO = 10 SEDIMENT_COUNT = 250*TANK_RATIO SEDIMENT_RADIUS = 1e-2 -DISCRETIZATION = 512 +DISCRETIZATION = 128 # initialize vorticity def init_vorticity(data, coords, component=None): @@ -21,6 +21,7 @@ def init_velocity(data, coords, component=None): d[...] = 0.0 def init_sediment(data, coords, nblobs, rblob): + from hysop import vprint data = data[0] coords = coords[0] X, Y = coords @@ -30,7 +31,7 @@ def init_sediment(data, coords, nblobs, rblob): str(abs(hash((TANK_RATIO,nblobs,rblob))))) try: D = np.load(file=cache_file+'.npz') - print ' *Initializing sediments from cache: "{}.npz".'.format(cache_file) + vprint(' *Initializing sediments from cache: "{}.npz".'.format(cache_file)) data[...] = D['data'] except: # this just explodes the RAM @@ -92,14 +93,14 @@ def init_sediment(data, coords, nblobs, rblob): if (d<R2): data[ii,jj] = 0.5 - print ' *Initializing sediments of radius {} with {} random blobs.'.format(rblob, nblobs) + vprint(' *Initializing sediments of radius {} with {} random blobs.'.format(rblob, nblobs)) data[...] = 0.0 iter_blobs(*args) #data[:int(0.05*Ny),:] = 1.0 # we cache initialization np.savez_compressed(file=cache_file, data=data) - print ' *Caching data to "{}.npz".'.format(cache_file) + vprint(' *Caching data to "{}.npz".'.format(cache_file)) diff --git a/hysop/backend/device/codegen/kernels/directional_advection.py b/hysop/backend/device/codegen/kernels/directional_advection.py index 7a5a0b438..594380a69 100644 --- a/hysop/backend/device/codegen/kernels/directional_advection.py +++ b/hysop/backend/device/codegen/kernels/directional_advection.py @@ -286,6 +286,7 @@ class DirectionalAdvectionKernelGenerator(KernelCodeGenerator): nparticles = s.nparticles min_ghosts = s.min_ghosts field_infos = s.field_infos + tuning_mode = s.tuning_mode symbolic_mode = s.symbolic_mode use_short_circuit = s.use_short_circuit @@ -584,11 +585,19 @@ class DirectionalAdvectionKernelGenerator(KernelCodeGenerator): s.jumpline() if is_cached and not has_bilevel: - code='event_t event = async_work_group_copy({dst}, {src}, {ne}, {event});'.format( - dst=Vc, src=line_velocity, ne=V_cache_width, event=0) - s.append(code) - code = 'wait_group_events(1, &event);' - s.append(code) + if tuning_mode: + loop = 'int {i}={Lx}; {i}<{N}; {i}+={gsize}'.format( + i='idx', N=V_cache_width, + Lx=local_id[0], gsize=local_size[0]) + with s._for_(loop): + code='{dst}[{i}] = 0.0;'.format(i='idx', dst=Vc) + s.append(code) + else: + code='event_t event = async_work_group_copy({dst}, {src}, {ne}, {event});'.format( + dst=Vc, src=line_velocity, ne=V_cache_width, event=0) + s.append(code) + code = 'wait_group_events(1, &event);' + s.append(code) s.jumpline() elif has_bilevel and not velocity_cache_full_length: # We must load velocity cache line on the fly diff --git a/hysop/backend/device/opencl/autotunable_kernels/advection_dir.py b/hysop/backend/device/opencl/autotunable_kernels/advection_dir.py index 9c8ef420c..813fab8b9 100644 --- a/hysop/backend/device/opencl/autotunable_kernels/advection_dir.py +++ b/hysop/backend/device/opencl/autotunable_kernels/advection_dir.py @@ -62,9 +62,6 @@ class OpenClAutotunableDirectionalAdvectionKernel(OpenClAutotunableKernel): eps = npw.finfo(precision).eps dt = velocity_cfl - velocity.fill(1.0) - velocity.exchange_ghosts() - make_offset, offset_dtype = self.make_array_offset() make_strides, strides_dtype = self.make_array_strides(position.dim, diff --git a/hysop/operator/adapt_timestep.py b/hysop/operator/adapt_timestep.py index 68fee1950..72265f377 100755 --- a/hysop/operator/adapt_timestep.py +++ b/hysop/operator/adapt_timestep.py @@ -139,7 +139,7 @@ class ConstantTimestepCriteria(TimestepCriteria): else: assert Finf.min() >= 0 mask = (Finf!=0) - dt = npw.zeros_like(cst, fill_value=npw.inf) + dt = npw.full_like(cst, fill_value=npw.inf) dt[mask] = cst[mask] / Finf[mask] return dt.min() diff --git a/hysop/operator/base/external_force.py b/hysop/operator/base/external_force.py new file mode 100644 index 000000000..0fd15eaee --- /dev/null +++ b/hysop/operator/base/external_force.py @@ -0,0 +1,157 @@ + + + +from abc import abstractmethod +from hysop.constants import SpectralTransformAction +from hysop.tools.numpywrappers import npw +from hysop.tools.types import check_instance, first_not_None, to_tuple +from hysop.tools.decorators import debug +from hysop.tools.numerics import float_to_complex_dtype +from hysop.fields.continuous_field import Field +from hysop.operator.base.spectral_operator import SpectralOperatorBase +from hysop.topology.cartesian_descriptor import CartesianTopologyDescriptors +from hysop.fields.continuous_field import Field +from hysop.symbolic.relational import Assignment +from hysop.core.memory.memory_request import MemoryRequest +from hysop.operator.external_force import ExternalForce +from hysop.parameters.tensor_parameter import TensorParameter +from hysop.parameters.scalar_parameter import ScalarParameter + +class SpectralExternalForceOperatorBase(SpectralOperatorBase): + """ + Compute the curl of a symbolic expression and perfom Euler time integration. + """ + + @debug + def __init__(self, vorticity, Fext, dt, variables, + Fmin=None, Fmax=None, Finf=None, + implementation=None, **kwds): + """ + Create an operator that computes the curl of a given input force field Fext. + + Only the following configurations are supported: + dim nb_components | dim nb_components + vorticity: 2 1 | 3 3 + + What is computed: + tmp = curl(Fext) by using a spectral backend + Fmin = min(tmp) + Fmax = max(tmp) + Finf = max(abs(Fmin), abs(Fmax)) + W += dt*tmp + + where Fext is computed from user given ExternalForce. + + Parameters + ---------- + vorticity: hysop.field.continuous_field.Field + Continuous field as input ScalarField or VectorField. + All contained field have to live on the same domain. + Fext: hysop.operator.external_force.ExternalForce + Expression of the external force. + F...: TensorParameter or boolean, optional + TensorParameters should match the shape of tmp (see Notes). + If set to True, the TensorParameter will be generated automatically. + variables: dict + dictionary of fields as keys and topologies as values. + kwds: dict, optional + Extra parameters passed towards base class (MultiSpaceDerivatives). + + Notes + ----- + If dim == 2, it is expected that: + vorticity has only one component + Fext has 2 components + Else if dim == 3: + vorticity has 3 components + Fext has 3 components + """ + check_instance(vorticity, Field) + check_instance(Fext, ExternalForce) + check_instance(dt, ScalarParameter) + check_instance(Fmin, (ScalarParameter,TensorParameter), allow_none=True) + check_instance(Fmax, (ScalarParameter,TensorParameter), allow_none=True) + check_instance(Finf, (ScalarParameter,TensorParameter), allow_none=True) + check_instance(variables, dict, keys=Field, values=CartesianTopologyDescriptors) + + # check fields + dim = vorticity.dim + w_components = vorticity.nb_components + f_components = Fext.dim + + if (dim==2): + if(w_components!=1): + msg='Vorticity components mistmach, got {} components but expected 1.' + msg=msg.format(w_components) + raise RuntimeError(msg) + if(f_components!=2): + msg='External force components mistmach, got {} components but expected 2.' + msg=msg.format(f_components) + raise RuntimeError(msg) + pshape = (1,) + elif (dim==3): + if(w_components!=3): + msg='Vorticity components mistmach, got {} components but expected 3.' + msg=msg.format(w_components) + raise RuntimeError(msg) + if(f_components!=3): + msg='External force components mistmach, got {} components but expected 3.' + msg=msg.format(f_components) + raise RuntimeError(msg) + pshape = (3,) + else: + msg='Unsupported dimension {}.'.format(dim) + raise RuntimeError(msg) + + msg='TensorParameter shape mismatch, expected {} but got {{}} for parameter {{}}.' + msg=msg.format(pshape) + if isinstance(Fmin, TensorParameter): + assert Fmin.shape==pshape, msg.format(Fmin.shape, 'Fmin') + Fmin = Fmin.view((0,)) if (dim==2) else Fmin + if isinstance(Fmax, TensorParameter): + assert Fmin.shape==pshape, msg.format(Fmax.shape, 'Fmax') + Fmax = Fmax.view((0,)) if (dim==2) else Fmax + if isinstance(Finf, TensorParameter): + assert Fmin.shape==pshape, msg.format(Finf.shape, 'Finf') + Finf = Finf.view((0,)) if (dim==2) else Finf + + # input and output fields + input_fields = Fext.input_fields() + input_fields.add(vorticity) + + output_fields = Fext.output_fields() + output_fields.add(vorticity) + + input_params = Fext.input_params() + input_params.add(dt) + + output_params = Fext.output_params() + output_params.update({Fmin,Fmax,Finf}) + output_params = output_params.difference({None}) + + input_fields = {f: self.get_topo_descriptor(variables, f) for f in input_fields} + output_fields = {f: self.get_topo_descriptor(variables, f) for f in output_fields} + input_params = {p.name: p for p in input_params} + output_params = {p.name: p for p in output_params} + + super(SpectralExternalForceOperatorBase, self).__init__( + input_fields=input_fields, output_fields=output_fields, + input_params=input_params, output_params=output_params, + **kwds) + + self.vorticity = vorticity + self.Fext = Fext + self.dim = dim + self.w_components = w_components + self.f_components = f_components + self.Fmin = Fmin + self.Fmax = Fmax + self.Finf = Finf + + @debug + def discretize(self): + if self.discretized: + return + super(SpectralExternalForceOperatorBase, self).discretize() + self.dW = self.get_input_discrete_field(self.vorticity) + diff --git a/hysop/operator/base/spectral_operator.py b/hysop/operator/base/spectral_operator.py index ae2ea513a..4d7a1a666 100644 --- a/hysop/operator/base/spectral_operator.py +++ b/hysop/operator/base/spectral_operator.py @@ -8,6 +8,7 @@ from hysop.constants import BoundaryCondition, BoundaryExtension, Transf from hysop.tools.misc import compute_nbytes from hysop.tools.types import check_instance, to_tuple, first_not_None from hysop.tools.decorators import debug +from hysop.tools.units import bytes2str from hysop.tools.numerics import is_fp, is_complex, complex_to_float_dtype, \ float_to_complex_dtype, determine_fp_types from hysop.tools.spectral_utils import SpectralTransformUtils as STU @@ -1477,7 +1478,12 @@ class PlannedSpectralTransform(object): verbose=False) fft_plan.setup(queue=queue) tmp_nbytes = max(tmp_nbytes, fft_plan.required_buffer_size) - + if (tmp_nbytes > nbytes): + msg='Planner claims to need more than buffer bytes as temporary buffer:' + msg+='\n *Buffer bytes: {}'.format(bytes2str(nbytes)) + msg+='\n *Tmp bytes: {}'.format(bytes2str(tmp_nbytes)) + raise RuntimeError(msg) + backend = self.transform_group.backend mem_tag = self.transform_group.mem_tag kind = backend.kind -- GitLab