I am trying to do something very similar to what Drummond has done with BCs, but in addition to functions of time, I am trying to modulate by some discrete function, e.g.
problem.add_bc("right(u) = - a * omega * sqrt(n**2 - omega**2)/omega * right(shape * cos(omega*t - kx*x))")
where shape is a field added as a parameter (but really only depends on x).
But now that shape is required to be a field, must I define the parity to decompose in the x direction? I receive the following error, which I think is related to the missing parity definition, but it's not evident how to add parity to this field/parameter.
Traceback (most recent call last):
File "boussinesqchebcos2D.py", line 143, in <module>
problem.add_bc("right(u) = - a * omega * sqrt(n**2 - omega**2)/omega * right(shape * cos(omega*t - kx*x))")
File "/Users/awink/dedalus/dedalus/core/problems.py", line 125, in add_bc
self._build_object_forms(temp)
File "/Users/awink/dedalus/dedalus/core/problems.py", line 142, in _build_object_forms
temp['RHS'] = future.FutureField.parse(temp['raw_RHS'], self.namespace, self.domain)
File "/Users/awink/dedalus/dedalus/core/future.py", line 223, in parse
expression = eval(string, namespace)
File "<string>", line 1, in <module>
File "/Users/awink/dedalus/dedalus/core/operators.py", line 1335, in right
return basis.Interpolate(arg0, 'right', out=out)
File "/Users/awink/dedalus/dedalus/core/operators.py", line 1257, in __new__
File "/Users/awink/dedalus/dedalus/tools/cache.py", line 29, in __get__
attribute = self.method(instance)
File "/Users/awink/dedalus/dedalus/core/future.py", line 178, in meta
meta[axis][key] = getattr(self, 'meta_%s' %key)(axis)
File "/Users/awink/dedalus/dedalus/core/operators.py", line 649, in meta_parity
return parity0 * parity1
TypeError: unsupported operand type(s) for *: 'NoneType' and 'int'
(I had previously accomplished this with the hacky helper function definitions defined after the problem definition.)
start_init_time = time.time()
x_basis = de.SinCos('x', Nx, interval=(-lx/2, lx/2), dealias=3/2)
z_basis = de.Chebyshev('z',Nz, interval=(-lz/2, lz/2), dealias=3/2)
domain = de.Domain([x_basis, z_basis], grid_dtype=np.float64)
x = domain.grid(0)
z = domain.grid(1)
xg, zg = np.meshgrid(x,np.transpose(z))
envelope = shapes.envelope(x,'Tophat',width,position).T
shapefield = np.zeros_like(xg)
for i in range(Nz):
shapefield[i,:] = envelope
shape = domain.new_field()
shape['g'] = shapefield.T
# 2D Boussinesq Hydrodynamics
problem = de.IVP(domain, variables=['u','w','P','rho','u_z','w_z','rho_z'],time='t')
problem.meta['P','w','w_z','rho','rho_z']['x']['parity'] = 1
problem.meta['u','u_z']['x']['parity'] = -1
problem.parameters['Re'] = Re # = \lambda*v_phase/\nu
problem.parameters['Fr'] = Fr # = v_phase^2/(g*l\ambda)
problem.parameters['Sc'] = Sc # = \nu/D
problem.parameters['eta'] = eta # d\rho/dz
problem.parameters['omega'] = omega # = 2*pi
problem.parameters['n'] = n # = N/Omega
problem.parameters['shape'] = shape
problem.parameters['a'] = a
problem.parameters['kx'] = kx
problem.add_equation("dt(u) - 1/Re*(dx(dx(u)) + dz(u_z)) + dx(P) = - u*dx(u) - w*dz(u)")
problem.add_equation("dt(w) - 1/Re*(dx(dx(w)) + dz(w_z)) + dz(P) + 1/Fr*(rho) = - u*dx(w) - w*dz(w)") # Momentum
problem.add_equation("dt(rho) - 1/(Sc*Re)*(dx(dx(rho)) + dz(rho_z)) + w*eta = - u*dx(rho) - w*dz(rho)") # Density
problem.add_equation("dx(u) + w_z = 0") # Incompressible Continuity
problem.add_equation("dz(w) - w_z = 0")
problem.add_equation("dz(u) - u_z = 0")
problem.add_equation("dz(rho) - rho_z = 0") # Derivative Definitions
problem.add_bc("left(u) = 0") # Stress free: u_z = 0, dx(w) = 0
problem.add_bc("left(w) = 0", condition="(dx != 0)") # Need 6 BCs in z for each of 6 z differential equations
problem.add_bc("left(rho) = 0")
problem.add_bc("right(u) = - a * omega * sqrt(n**2 - omega**2)/omega * right(shape * cos(omega*t - kx*x))")
problem.add_bc("right(w) = a * omega * right(shape * cos(omega*t - kx*x))")
problem.add_bc("right(rho) = - a * eta * right(shape * sin(omega*t - kx*x))")
problem.add_bc("integ_z(P) = 0", condition="(dx == 0)") # Fixed Boundaries (Uses freed up mode, dx=i*k_x=0, to set gauge P.)
solver = problem.build_solver(de.timesteppers.SBDF3)