diff --git a/examples/particles_above_salt/particles_above_salt_symmetrized.py b/examples/particles_above_salt/particles_above_salt_symmetrized.py index d26e0873dd427db6dca885594177e58325923864..621badee6c55a87720463f659ffffefcf3418397 100644 --- a/examples/particles_above_salt/particles_above_salt_symmetrized.py +++ b/examples/particles_above_salt/particles_above_salt_symmetrized.py @@ -30,7 +30,7 @@ def delta(Ys, l0): def init_concentration(data, coords, l0): X = coords[-1].copy() - X = 600.0 - np.abs(X-1200.0) + X = np.abs(X-1200.0) - 600.0 Ys = coords[:-1] data[0][...] = 0.5*(1.0 + sp.special.erf((X-delta(Ys,l0))/l0)) @@ -132,12 +132,14 @@ def compute(args): advected_fields = (vorti,S), velocity_cfl = args.cfl, variables = {velo: npts, vorti: npts, S: npts}, - dt=dt) + dt=dt, **extra_op_kwds) + # mirror sediment settling speed at Y=1200 (Y in [0..2400]) VP = [0]*dim - VP[-1] = 'Select({},{},gidx.y<{})'.format(tg.dump(-Vp), - tg.dump(+Vp), - (npts[0]-1)//2) + VP[-1] = 'select({}, {}, field_infos->P.pos.X<{})'.format( + tg.dump(-Vp), + tg.dump(+Vp), + tg.dump(1200.0)) advec_C = DirectionalAdvection(implementation=impl, name='advec_C', @@ -146,7 +148,7 @@ def compute(args): relative_velocity = VP, velocity_cfl = args.cfl, variables = {velo: npts, C: npts}, - dt=dt) + dt=dt, **extra_op_kwds) #> Stretch and diffuse vorticity if (dim==3): @@ -348,8 +350,8 @@ if __name__=='__main__': box_origin=(0.0,), box_length=(1.0,), tstart=0.0, tend=500.0, dt=1e-6, cfl=0.5, lcfl=0.125, - dump_times=tuple(float(x) for x in range(500)), - dump_freq=0) + dump_times=None,#tuple(float(x) for x in range(500)), + dump_freq=100) parser.run(compute) diff --git a/hysop/backend/device/codegen/base/variables.py b/hysop/backend/device/codegen/base/variables.py index b96c6e458715eb6ae3fb0881cc2d17583bf35a59..3924583104befe1d7e844c9ec012d85006a77b7d 100644 --- a/hysop/backend/device/codegen/base/variables.py +++ b/hysop/backend/device/codegen/base/variables.py @@ -237,7 +237,7 @@ class CodegenVariable(object): ptr_const = self.ptr_const if (ptr_const is None) else ptr_const ptr_volatile = self.ptr_volatile if (ptr_volatile is None) else ptr_volatile ptr_restrict = self.ptr_restrict if (ptr_restrict is None) else ptr_restrict - + return cls(name=name, nl=nl, value=value, svalue=svalue, init=init, ctype=ctype, storage=storage, @@ -914,6 +914,11 @@ class CodegenStruct(CodegenVariable): struct_var=struct_var) self.genvars(struct, var_overrides) + + + def newvar(self, *args, **kwds): + kwds.setdefault('cls', CodegenVariable) + return super(CodegenStruct, self).newvar(*args, **kwds) def force_symbolic(self, force=True): if force is None: @@ -936,7 +941,7 @@ class CodegenStruct(CodegenVariable): else: raise AttributeError - def genvars(self,struct,var_overrides): + def genvars(self, struct, var_overrides): if var_overrides is None: var_overrides = {} diff --git a/hysop/backend/device/codegen/functions/advection_rhs.py b/hysop/backend/device/codegen/functions/advection_rhs.py index 9a4e7fe5bc9981e3713098d024ca4103bb377da3..08ce04c49eb2556daae7b9839202977cabd3f8ca 100644 --- a/hysop/backend/device/codegen/functions/advection_rhs.py +++ b/hysop/backend/device/codegen/functions/advection_rhs.py @@ -21,7 +21,8 @@ class DirectionalAdvectionRhsFunction(OpenClFunctionCodeGenerator): relative_velocity, ptr_restrict=True, itype='int', - known_args=None): + known_args=None, + field_infos=None): assert work_dim>=1 and work_dim<=3 check_instance(boundary,BoundaryCondition) @@ -38,7 +39,7 @@ class DirectionalAdvectionRhsFunction(OpenClFunctionCodeGenerator): vtype = typegen.vtype(ftype,nparticles) (args,basename) = self.build_prototype(typegen,work_dim,itype,ftype,vtype, - nparticles,ptr_restrict,storage,is_cached, is_periodic) + nparticles,ptr_restrict,storage,is_cached, is_periodic, field_infos) reqs = self.build_requirements(typegen,work_dim,itype,ftype,vtype, nparticles,ptr_restrict,storage,is_cached, is_periodic) @@ -65,7 +66,7 @@ class DirectionalAdvectionRhsFunction(OpenClFunctionCodeGenerator): self.gencode() def build_prototype(self, typegen, work_dim, itype, ftype, vtype, - nparticles, ptr_restrict, storage, is_cached, is_periodic): + nparticles, ptr_restrict, storage, is_cached, is_periodic, field_infos): args = ArgDict() @@ -74,8 +75,6 @@ class DirectionalAdvectionRhsFunction(OpenClFunctionCodeGenerator): nl=True) args['X'] = CodegenVectorClBuiltin('X', ftype, nparticles, typegen, add_impl_const=True, nl=True) - #args['gidx'] = CodegenVectorClBuiltin('gidx', ftype, nparticles, typegen, add_impl_const=True, - #nl=True) if is_periodic and (not is_cached): args['line_width'] = CodegenVariable('line_width', itype, typegen, @@ -87,6 +86,10 @@ class DirectionalAdvectionRhsFunction(OpenClFunctionCodeGenerator): args['inv_dx'] = CodegenVariable('inv_dx', ftype, typegen, add_impl_const=True, nl=True) # args['active'] = CodegenVariable('active','bool',typegen, add_impl_const=True) + if (field_infos is not None): + args['field_infos'] = field_infos.pointer(name='field_infos', ptr_level=1, + const=True, ptr_const=True, nl=True) + cached = 'cached_' if is_cached else '' basename = 'advection_rhs_{}{}{}p'.format(cached, ftype[0], nparticles) diff --git a/hysop/backend/device/codegen/kernels/directional_advection.py b/hysop/backend/device/codegen/kernels/directional_advection.py index 75b17be9f5b7217d07c30643aa0310ad2282d200..5d66ff58af650d2e038bc4db54f469afc9296abc 100644 --- a/hysop/backend/device/codegen/kernels/directional_advection.py +++ b/hysop/backend/device/codegen/kernels/directional_advection.py @@ -24,8 +24,9 @@ from hysop.backend.device.opencl.opencl_array_backend import OpenClArrayBackend from hysop.backend.device.codegen.base.utils import WriteOnceDict, ArgDict from hysop.backend.device.codegen.base.statistics import WorkStatistics -from hysop.backend.device.codegen.base.variables import CodegenStruct -from hysop.backend.device.codegen.structs.mesh_info import MeshBaseStruct, MeshInfoStruct +from hysop.backend.device.codegen.base.variables import CodegenStruct +from hysop.backend.device.codegen.structs.mesh_info import MeshBaseStruct, MeshInfoStruct +from hysop.backend.device.codegen.structs.indices import GlobalFieldInfos from hysop.backend.device.codegen.functions.runge_kutta import RungeKuttaFunction from hysop.backend.device.codegen.functions.advection_rhs import DirectionalAdvectionRhsFunction @@ -194,13 +195,21 @@ class DirectionalAdvectionKernelGenerator(KernelCodeGenerator): mesh_info_struct = MeshInfoStruct(typegen=typegen, vsize=vsize) reqs['MeshInfoStruct'] = mesh_info_struct + + field_names = ('V','P') + global_field_infos = GlobalFieldInfos(typegen=typegen, field_names=field_names, + workdim=work_dim, vsize=nparticles) + reqs['GlobalFieldInfos'] = global_field_infos + self.field_names = field_names + self.field_infos = global_field_infos.build_codegen_variable(name='field_infos') + advection_rhs = DirectionalAdvectionRhsFunction(typegen=typegen, work_dim=work_dim, ftype=ftype, is_cached=is_cached, boundary=vboundary[0], nparticles=nparticles, relative_velocity=relative_velocity, ptr_restrict=True, - itype=itype) + itype=itype, field_infos=self.field_infos) used_vars = RungeKuttaFunction._default_used_vars.copy() used_vars['y']='X' @@ -263,6 +272,7 @@ class DirectionalAdvectionKernelGenerator(KernelCodeGenerator): storage = s.storage nparticles = s.nparticles min_ghosts = s.min_ghosts + field_infos = s.field_infos symbolic_mode = s.symbolic_mode use_short_circuit = s.use_short_circuit @@ -271,7 +281,8 @@ class DirectionalAdvectionKernelGenerator(KernelCodeGenerator): is_cached = s.is_cached cache_size_known = s.cache_size_known - vtype = tg.vtype(ftype,work_dim) + vtype = tg.vtype(ftype, work_dim) + pvtype = tg.vtype(ftype, nparticles) global_id = s.vars['global_id'] local_id = s.vars['local_id'] @@ -307,13 +318,7 @@ class DirectionalAdvectionKernelGenerator(KernelCodeGenerator): position_gid = CodegenVectorClBuiltin('P_gid', itype, work_dim, typegen=tg) velocity_gid = CodegenVectorClBuiltin('V_gid', itype, work_dim, typegen=tg) - global_ids = {} - for fname in ['V', 'P']: - global_ids[fname] = [CodegenVariable('{}_K{}'.format(fname, - DirectionLabels[work_dim-1-i]), - itype, const=True, typegen=tg) for i in xrange(work_dim-1) ] - global_ids[fname] += [CodegenVectorClBuiltin('{}_KX'.format(fname), itype, - nparticles, typegen=tg, const=True)] + runge_kutta = self.reqs['runge_kutta'] @@ -391,12 +396,16 @@ class DirectionalAdvectionKernelGenerator(KernelCodeGenerator): line_work, advec_ghosts)) s.jumpline() - for (k,v) in global_ids.iteritems(): + for k in s.field_names: + v = field_infos[k] + v0 = '{}.idx.IX'.format(v) + v1 = '{}.pos.X'.format(v) mi = s.vars['{}_mesh_info'.format(k)] - v[-1].declare(codegen=s, init='{} + {} + {}'.format( - mi['start'][0], - line_offset, - poffset)) + s.append('{} = {} + {} + {};'.format(v0, mi['start'][0], line_offset, poffset)) + s.append('{} = {} + convert_{}({})*{};'.format(v1, mi['global_mesh']['xmin'][0], + pvtype, v0, mi['dx'][0])) + s.jumpline() + position_gid.affect(i=0, codegen=s, init='{} + {}'.format( line_offset, position_ghosts)) velocity_gid.affect(i=0, codegen=s, init='{} + {} - {}'.format( @@ -415,10 +424,17 @@ class DirectionalAdvectionKernelGenerator(KernelCodeGenerator): line_position.declare(al, init='{} + {}'.format(position, line_position_offset), align=True) else: - for (k,v) in global_ids.iteritems(): + for k in s.field_names: + v = field_infos[k] + d = DirectionLabels[i] + v0 = '{}.idx.I{}'.format(v, d) + v1 = '{}.pos.{}'.format(v, d) mi = s.vars['{}_mesh_info'.format(k)] - v[work_dim-1-i].declare(codegen=s, - init='{} + {}'.format(mi['start'][i],'kji'[i])) + s.append('{} = {} + {};'.format(v0, mi['start'][i], 'kji'[i])) + s.append('{} = {} + {}*{};'.format(v1, mi['global_mesh']['xmin'][i], + v0, mi['dx'][i])) + s.jumpline() + s.append('{} = {} + {};'.format(position_gid[i], 'kji'[i], position_ghosts)) s.append('{} = {} + {};'.format(velocity_gid[i], 'kji'[i], @@ -429,6 +445,7 @@ class DirectionalAdvectionKernelGenerator(KernelCodeGenerator): nested_loops = [_work_iterate_(i) for i in xrange(work_dim-1,-1,-1)] with s._kernel_(): + field_infos.declare(s) s.jumpline() with s._align_() as al: global_id.declare(al,align=True,const=True) @@ -491,7 +508,8 @@ class DirectionalAdvectionKernelGenerator(KernelCodeGenerator): 'X': X, 'dt': dt, 'inv_dx': inv_dx, - 'line_offset': line_offset + 'line_offset': line_offset, + 'field_infos': '&{}'.format(field_infos), } if is_cached: rk_args['line_velocity'] = Vc diff --git a/hysop/backend/device/codegen/structs/indices.py b/hysop/backend/device/codegen/structs/indices.py new file mode 100644 index 0000000000000000000000000000000000000000..dfe81ca3cd108b75189f6306b226ba23c41a02e9 --- /dev/null +++ b/hysop/backend/device/codegen/structs/indices.py @@ -0,0 +1,141 @@ + +from hysop.deps import np +from hysop.tools.types import check_instance, first_not_None +from hysop.tools.misc import upper_pow2_or_3 +from hysop.backend.device.codegen.base.enum_codegen import EnumCodeGenerator +from hysop.backend.device.codegen.base.struct_codegen import StructCodeGenerator +from hysop.backend.device.opencl.opencl_types import OpenClTypeGen +from hysop.constants import DirectionLabels + +class SpaceIndices(StructCodeGenerator): + def __init__(self, name, typegen, var_prefix, stype, workdim, + vsize=1, typedef=True, comments=None): + assert vsize in [1,2,3,4,8,16] + stype = stype.replace('fbtype', typegen.fbtype) + name += '{}D_{}{}'.format(workdim, stype.capitalize(), vsize) + if isinstance(typedef, bool): + if (typedef is True): + typedef = name+'_s' + else: + typedef = None + dtype = self.build_dtype(typegen, var_prefix, stype, vsize, workdim) + super(SpaceIndices, self).__init__(name=name, + dtype=dtype, + typegen=typegen, + typedef=typedef, + comments=comments) + self.workdim = workdim + self.vsize = vsize + self.stype = stype + + @staticmethod + def build_dtype(typegen, var_prefix, stype, vsize, workdim): + tg = typegen + stype1 = tg.dtype_from_str(stype) + stypen = tg.dtype_from_str('{}{}'.format(stype, vsize)) + + dtype = [] + + fn = '{}{}'.format(var_prefix, DirectionLabels[0]) + field = (fn, stypen) + dtype.append(field) + + for i in xrange(workdim-2, -1, -1): + fn = '{}{}'.format(var_prefix, DirectionLabels[workdim-1-i]) + field = (fn, stype1) + dtype.append(field) + + + return np.dtype(dtype) + + def create(self, *args, **kwds): + raise NotImplementedError() + + +class GlobalIndices(SpaceIndices): + def __init__(self, typegen, workdim, **kwds): + super(GlobalIndices, self).__init__( + typegen=typegen, workdim=workdim, + name='GlobalIndices', var_prefix='I', stype='int', + **kwds) + +class GlobalCoordinates(SpaceIndices): + def __init__(self, typegen, workdim, **kwds): + super(GlobalCoordinates, self).__init__( + typegen=typegen, workdim=workdim, + name='GlobalCoordinates', var_prefix='', stype='fbtype', + **kwds) + +class GlobalFieldInfo(StructCodeGenerator): + def __init__(self, typegen, workdim, vsize, typedef=True, **kwds): + gi = GlobalIndices(typegen=typegen, workdim=workdim, vsize=vsize) + gc = GlobalCoordinates(typegen=typegen, workdim=workdim, vsize=vsize) + dtype = self.build_dtype(gi, gc) + name='GlobalFieldInfo{}D_{}{}_{}{}'.format(workdim, + gi.stype.capitalize(), vsize, + gc.stype.capitalize(), vsize) + if isinstance(typedef, bool): + if (typedef is True): + typedef = name+'_s' + else: + typedef = None + super(GlobalFieldInfo, self).__init__(name=name, + dtype=dtype, + typedef=typedef, + typegen=typegen, + **kwds) + self.require(gi.name, gi) + self.require(gc.name, gc) + self.workdim = workdim + self.vsize = vsize + + @staticmethod + def build_dtype(gi, gc): + dtype = [('idx', gi.dtype), ('pos', gc.dtype)] + return np.dtype(dtype) + +class GlobalFieldInfos(StructCodeGenerator): + def __init__(self, field_names, typegen, workdim, vsize, typedef=True, **kwds): + gfi = GlobalFieldInfo(typegen=typegen, workdim=workdim, vsize=vsize) + dtype = [] + for fname in field_names: + field = (fname, gfi.dtype) + dtype.append(field) + dtype = np.dtype(dtype) + name = gfi.name.replace('GlobalFieldInfo', 'GlobalFieldInfos') + name += '_' + '_'.join(field_names) + if isinstance(typedef, bool): + if (typedef is True): + typedef = name+'_s' + else: + typedef = None + super(GlobalFieldInfos, self).__init__(name=name, + dtype=dtype, + typedef=typedef, + typegen=typegen, + **kwds) + self.require(gfi.name, gfi) + self.field_names = field_names + self.workdim = workdim + self.vsize = vsize + + +if __name__ == '__main__': + from hysop.backend.device.codegen.base.opencl_codegen import OpenClCodeGenerator + from hysop.backend.device.codegen.base.test import _test_typegen + + tg = _test_typegen('double', float_dump_mode='dec') + + idx = GlobalIndices(typegen=tg, workdim=3, vsize=4) + pos = GlobalCoordinates(typegen=tg, workdim=3, vsize=4) + gfi = GlobalFieldInfo(typegen=tg, workdim=3, vsize=2) + gfis = GlobalFieldInfos(typegen=tg, workdim=2, vsize=8, field_names=('P','V')) + + cg = OpenClCodeGenerator('test_generator',tg) + cg.require('idx', idx) + cg.require('pos', pos) + cg.require('gfi', gfi) + cg.require('gfis', gfis) + + cg.edit() + cg.test_compile()