diff --git a/examples/particles_above_salt/particles_above_salt_periodic.py b/examples/particles_above_salt/particles_above_salt_periodic.py index f521f51417ec784066d7fdfb0c1f5326cce125e4..30b8cb2062837e284d53094d6b96bc72839e685d 100644 --- a/examples/particles_above_salt/particles_above_salt_periodic.py +++ b/examples/particles_above_salt/particles_above_salt_periodic.py @@ -21,12 +21,18 @@ def init_velocity(data, coords): def delta(*coords): d = np.prod(*coords) return np.zeros_like(d) + +def delta(Ys, l0): + Y0 = 1 + for Yi in Ys: + Y0 = Y0*Yi + return 0.1*l0*(np.random.rand(*Y0.shape)-0.5) def init_concentration(data, coords, l0): X = coords[-1] - C = coords[:-1] + Ys = coords[:-1] data[0][...] = 0.5*(1.0 + - sp.special.erf(2*np.abs(4*X-2) - 2)) + sp.special.erf((X-delta(Ys,l0))/l0)) def init_salinity(data, coords, l0): init_concentration(data, coords, l0) @@ -52,10 +58,10 @@ def compute(args): from hysop.methods import SpaceDiscretization, Remesh, TimeIntegrator, \ ComputeGranularity, Interpolation - from hysop.symbolic import sm, space_symbols + from hysop.symbolic import sm, space_symbols, local_indices_symbols from hysop.symbolic.base import SymbolicTensor from hysop.symbolic.field import curl - from hysop.symbolic.relational import Assignment, LogicalGT, LogicalLT + from hysop.symbolic.relational import Assignment, LogicalGE, LogicalLT, LogicalOR, LogicalGT from hysop.symbolic.misc import Select from hysop.symbolic.tmp import TmpScalar from hysop.tools.string_utils import framed_str @@ -64,17 +70,18 @@ def compute(args): l0 = 1.5 #initial thickness of the profile #(Sc, tau, Vp, Rs, Xo, Xn, N) = (10.0, 10, 0.00, 2.0, (-28.13, 0.0, 0.0), (+28.13, 28.13, 28.13), (385,128,128)) # large Sc (linear validation) #(Sc, tau, Vp, Rs, Xo, Xn, N) = (1.00, 100, 0.00, 2.0, (-20.00, 0.0, 0.0), (+20.00, 20.00, 20.00), (385,128,128)) # small Sc (linear validation) - (Sc, tau, Vp, Rs, Xo, Xn, N) = (0.70, 25, 0.04, 2.0, (-300,0), (300,750), (1537, 512)) # 2d configuration (DNS) + (Sc, tau, Vp, Rs, Xo, Xn, N) = (0.70, 25, 0.04, 2.0, (-600,0), (600,750), (1537, 512)) # 2d configuration (DNS) #(Sc, tau, Vp, Rs, Xo, Xn, N) = (7.00, 25, 0.04, 2.0, (-110,0,0), (65,100,100), (1537, 512, 512)) # 3d configuration (DNS) nu_S = 1.0/Sc nu_C = 1.0/(tau*Sc) + l0*=10 # Define the domain dim = args.ndim L = np.subtract(Xn, Xo) - npts=args.npts - box = Box(dim=dim) + npts=N + box = Box(origin=Xo, length=np.subtract(Xn,Xo)) # Get default MPI Parameters from domain (even for serial jobs) mpi_params = MPIParams(comm=box.task_comm, @@ -114,11 +121,28 @@ def compute(args): # Symbolic fields frame = velo.domain.frame + Us = velo.s(*frame.vars) Ws = vorti.s(*frame.vars) Cs = C.s(*frame.vars) Ss = S.s(*frame.vars) + dts = dt.s ### Build the directional operators + #> Directional penalization + zs = space_symbols[0] + Zs, Ze = Xo[0], Xn[0] + Lz = Zs-Ze + cond = LogicalOR(LogicalLT(zs, Zs+0.25*Lz), LogicalGE(zs, Ze-0.25*Lz)) + lambda_ = cond*1.0e8 + penalization = -lambda_*dts*Us / (1+lambda_*dts) + lhs = Ws + rhs = Ws + curl(penalization, frame) + exprs = Assignment.assign(lhs, rhs) + penalization = DirectionalSymbolic(name='penalization', + implementation=impl, + exprs=exprs, dt=dt, + variables={vorti: npts, velo: npts}, + **extra_op_kwds) #> Directional advection advec = DirectionalAdvection(implementation=impl, name='advec', @@ -170,7 +194,8 @@ def compute(args): #> External force rot(-rho*g) = rot(Rs*S + C) Fext = np.zeros(shape=(dim,), dtype=object).view(SymbolicTensor) - Fext[0] = (Rs*Ss + Cs) + fext = -(Rs*Ss + Cs) + Fext[-1] = fext lhs = Ws.diff(frame.time) rhs = curl(Fext, frame) exprs = Assignment.assign(lhs, rhs) @@ -181,6 +206,10 @@ def compute(args): S: npts, C: npts}, **extra_op_kwds) + + splitting_penalization = StrangSplitting(splitting_dim=dim, + order=args.strang_order) + splitting_penalization.push_operators(penalization) splitting = StrangSplitting(splitting_dim=dim, order=args.strang_order) @@ -210,7 +239,7 @@ def compute(args): S: npts}) ### Adaptive timestep operator - dx = np.min(np.divide(box.length, np.asarray(args.npts)-1)) + dx = np.min(np.divide(box.length, np.asarray(npts)-1)) S_dt = 0.5*(dx**2)/nu_S C_dt = 0.5*(dx**2)/nu_C W_dt = 0.5*(dx**2)/1.0 @@ -222,7 +251,7 @@ def compute(args): adapt_dt = AdaptiveTimeStep(dt, equivalent_CFL=True, max_dt=max_dt, name='merge_dt', pretty_name='dt', ) - dt_cfl = adapt_dt.push_cfl_criteria(cfl=args.cfl, Finf=min_max_U.Finf, + dt_cfl = adapt_dt.push_cfl_criteria(cfl=args.cfl, Finf=min_max_U.Finf, equivalent_CFL=True, name='dt_cfl', pretty_name='CFL') dt_advec = adapt_dt.push_advection_criteria(lcfl=args.lcfl, Finf=min_max_W.Finf, @@ -246,6 +275,7 @@ def compute(args): problem = Problem(method=method) problem.insert(poisson, + splitting_penalization, splitting, dump_fields, min_max_U, min_max_W, @@ -313,7 +343,7 @@ if __name__=='__main__': parser.set_defaults(impl='cl', ndim=2, npts=(65,), box_origin=(0.0,), box_length=(1.0,), - tstart=0.0, tend=0.51, + tstart=0.0, tend=500.0, dt=1e-6, cfl=0.5, lcfl=0.125, dump_freq=10) diff --git a/hysop/backend/device/opencl/opencl_copy_kernel_launchers.py b/hysop/backend/device/opencl/opencl_copy_kernel_launchers.py index 256fd904cf5638ffb26317767799660f5e6eff5f..02c08639358c7be00d0580e1f8046e90b9d0ab54 100644 --- a/hysop/backend/device/opencl/opencl_copy_kernel_launchers.py +++ b/hysop/backend/device/opencl/opencl_copy_kernel_launchers.py @@ -319,6 +319,10 @@ class OpenClCopyBufferRectLauncher(OpenClCopyKernelLauncher): # compute indices indices = () for slc, si in zip(slices, shape): + if (slc.stop is not None) and (slc.stop > si): + msg='Error in slice specification: slc={} but size is only {}.' + msg=msg.format(slc, si) + raise ValueError(msg) if isinstance(slc, slice): indices += (slc.indices(si),) else: diff --git a/hysop/symbolic/directional.py b/hysop/symbolic/directional.py index 00ee06ff2b32df5a63a60cdff4c64c9b60c4f0da..62185b1b8e8f594547ed286cf6d446273cccac85 100644 --- a/hysop/symbolic/directional.py +++ b/hysop/symbolic/directional.py @@ -1,8 +1,10 @@ +import warnings from hysop.deps import np, sm from hysop.tools.types import first_not_None, check_instance from hysop.symbolic import space_symbols from hysop.symbolic.field import div, grad +from hysop.tools.warning import HysopWarning def collect_direction(expr, var): is_tensor = isinstance(expr, np.ndarray) @@ -38,11 +40,16 @@ def split(F, coords=None): coords = first_not_None(coords, space_symbols) for i, xi in enumerate(coords): res[i] = collect_direction(F, xi) - residue = (F - sum(res.values())).simplify() - count = sum((r != 0) for r in res.values()) - if (count>0): - for i in res.keys(): - res[i] += (residue/count) + try: + residue = (F - sum(res.values())).simplify() + count = sum((r != 0) for r in res.values()) + if (count>0): + for i in res.keys(): + res[i] += (residue/count) + except AttributeError: + msg='Failed to compute residue for expression {}.' + msg=msg.format(F) + warnings.warn(msg, HysopWarning) return res def split_assignement(expr, coords=None): diff --git a/hysop/symbolic/relational.py b/hysop/symbolic/relational.py index a4c77fffa4b7d17fdb4220b0bc2151ee382bc5fd..e7be59db2b39708de2f0556e40e0fbdb505b5518 100644 --- a/hysop/symbolic/relational.py +++ b/hysop/symbolic/relational.py @@ -35,6 +35,10 @@ class NAryRelation(Expr): @property def is_number(self): return True + + @property + def free_symbols(self): + return () class LogicalRelation(NAryRelation): pass