Dear Daniel,
Thank you for the suggestions. I have implemented them into Dedalus and unfortunately the density becomes less than zero in some regions and there is overflow (see the full details below).
I still suspect that the problem arises because of the constrain equation (Equation 2 below). I linearised it as much as I could but there are still velocity terms that have coefficients that are dependent on the other variables. This means the RHS has terms involving the velocity. Do you agree that this is causing the problem and if so how can I fix it?
Best,
Peter
I re-wrote the equations in my original post in terms of ln(rho) and linearised them as much as possible. The form of the equations that I inputted into Dedalus are as follows:
My code runs for 55 time units before I get an Overflow error. At this point the density becomes less than zero in some regions and I also noticed some unusual quadropoles in the vorticity field.
I tried reducing the time step, and changing the number of modes and the aliasing but I still get an Overflow error after around 55 time units.
The full code is
```
import numpy as np
import dedalus.public as d3
import logging
logger = logging.getLogger(__name__)
# Parameters
Nx, Ny = 256, 256
dealias = 3/2
timestepper = d3.RK222
max_timestep = 1e-1
Nsteps = 1000
dN = 100
k_d = 0.1
L = 1
b = 20
eta_rot = 1
beta = -0.2
lambdabar_sun = 6
lambdabar = 1.3*(1+2*np.sqrt(k_d))**2
kappa = -0.8
c = 4
a = 1/2*(lambdabar_sun+c)
Lx, Ly = 8*2*np.pi/(np.sqrt(np.sqrt(k_d))/np.sqrt(2)), 8*2*np.pi/(np.sqrt(np.sqrt(k_d))/np.sqrt(2))
stop_sim_time = Nsteps*max_timestep
sim_dt = dN*max_timestep
dtype = np.float64
# Bases
coords = d3.CartesianCoordinates('x', 'y')
dist = d3.Distributor(coords, dtype=dtype)
xbasis = d3.RealFourier(coords['x'], size=Nx, bounds=(-Lx/2, Lx/2), dealias=dealias)
ybasis = d3.RealFourier(coords['y'], size=Ny, bounds=(-Ly/2, Ly/2), dealias=dealias)
# Fields
lnrho = dist.Field(name='lnrho', bases=(xbasis,ybasis))
v = dist.VectorField(coords, name='v', bases=(xbasis,ybasis))
q = dist.TensorField((coords, coords), name='q', bases=(xbasis,ybasis))
# Substitutions
dx = lambda A: d3.Differentiate(A, coords['x'])
dy = lambda A: d3.Differentiate(A, coords['y'])
x, y = dist.local_grids(xbasis, ybasis)
ex, ey = coords.unit_vector_fields(dist)
identity = ex*ex+ey*ey
d = 1/2*(d3.grad(v) + d3.trans(d3.grad(v)))
w = 1/2*(d3.grad(v) - d3.trans(d3.grad(v)))
#qhat=d3.dt(q)+(v@ex)*dx(q)+(v@ey)*dy(q)-w@q+q@w
d_dev = d-d3.trace(d)/2*identity
sigmaprime = (2*(d+d3.trace(d)*identity)\
+beta*1/eta_rot*(-beta*d_dev-(2*a+b*2*d3.trace(q@q))*q+L*(d3.lap(q)+dx(lnrho)*dx(q)+dy(lnrho)*dy(q))+lambdabar_sun*np.exp(lnrho)*q)\
+lambdabar*(identity+kappa*q)\
-L*(2*(d3.grad(q@ex@ex)*d3.grad(q@ex@ex)+d3.grad(q@ex@ey)*d3.grad(q@ex@ey))\
-...@d3.div(d3.grad(q))-q@(dx(lnrho)*dx(q)+dy(lnrho)*dy(q))+d3.trans(q...@d3.div(d3.grad(q))+q@(dx(lnrho)*dx(q)+dy(lnrho)*dy(q)))))
sigmaprimelinear = (2*(d+d3.trace(d)*identity)\
+beta*1/eta_rot*(-beta*d_dev-(2*a)*q+L*(d3.lap(q)))\
+lambdabar*(kappa*q))
sigmaprimenonlinear = (beta*1/eta_rot*(-(b*2*d3.trace(q@q))*q+L*(dx(lnrho)*dx(q)+dy(lnrho)*dy(q))+lambdabar_sun*np.exp(lnrho)*q)\
+lambdabar*identity\
-L*(2*(d3.grad(q@ex@ex)*d3.grad(q@ex@ex)+d3.grad(q@ex@ey)*d3.grad(q@ex@ey))\
-...@d3.div(d3.grad(q))-q@(dx(lnrho)*dx(q)+dy(lnrho)*dy(q))+d3.trans(q...@d3.div(d3.grad(q))+q@(dx(lnrho)*dx(q)+dy(lnrho)*dy(q)))))
sigmaprimenonconstant = (2*(d+d3.trace(d)*identity)\
+beta*1/eta_rot*(-beta*d_dev-(2*a+b*2*d3.trace(q@q))*q+L*(d3.lap(q)+dx(lnrho)*dx(q)+dy(lnrho)*dy(q))+lambdabar_sun*np.exp(lnrho)*q)\
+lambdabar*(kappa*q)\
-L*(2*(d3.grad(q@ex@ex)*d3.grad(q@ex@ex)+d3.grad(q@ex@ey)*d3.grad(q@ex@ey))\
-...@d3.div(d3.grad(q))-q@(dx(lnrho)*dx(q)+dy(lnrho)*dy(q))+d3.trans(q...@d3.div(d3.grad(q))+q@(dx(lnrho)*dx(q)+dy(lnrho)*dy(q)))))
# Problem
problem = d3.IVP([lnrho, v, q], namespace=locals())
problem.add_equation("dt(lnrho)-lap(lnrho)+div(v) = (dx(lnrho)**2+dy(lnrho)**2)-k_d+k_d*np.exp(-lnrho) - v@grad(lnrho)")
problem.add_equation("v - div(sigmaprimelinear) - grad(lnrho)@(lambdabar*identity) = div(sigmaprimenonlinear)+grad(lnrho)@sigmaprimenonconstant")
problem.add_equation("eta_rot*dt(q)+beta*d_dev+2*a*q-L*lap(q)=\
-eta_rot*((v@ex)*dx(q)+(v@ey)*dy(q)-w@q+q@w)\
-b*2*trace(q@q)*q+L*(dx(lnrho)*dx(q)+dy(lnrho)*dy(q))+lambdabar_sun*np.exp(lnrho)*q")
# Solver
solver = problem.build_solver(timestepper)
solver.stop_sim_time = stop_sim_time
# Initial conditions
lnrho.fill_random('g', seed=42, distribution='normal', scale = 0.05)
lnrho = np.log(1+lnrho)
q.fill_random('g', seed=43, distribution='normal', scale = 0.05)
q['g'][1,0]=q['g'][0,1]
q['g'][1,1]=-q['g'][0,0]
# Analysis
snapshots = solver.evaluator.add_file_handler('snapshots', sim_dt=sim_dt, max_writes=10)
snapshots.add_task(np.exp(lnrho)-1, name='rho-1')
#snapshots.add_task(d3.div(v), name='divergence')
snapshots.add_task(np.sqrt(2*d3.trace(q@q)), name='q')
snapshots.add_task(-d3.div(d3.skew(v)), name='vorticity')
# CFL
CFL = d3.CFL(solver, initial_dt=max_timestep, cadence=10, safety=0.2, threshold=0.1, max_change=1.5, min_change=0.5, max_dt=max_timestep)
CFL.add_velocity(v)
# Flow properties
flow = d3.GlobalFlowProperty(solver, cadence=10)
# Main loop
try:
logger.info('Starting main loop')
while solver.proceed:
timestep = CFL.compute_timestep()
solver.step(timestep)
if (solver.iteration-1) % 100 == 0:
#max_w = np.sqrt(flow.max('w2'))
logger.info('Iteration=%i, Time=%e, dt=%e' %(solver.iteration, solver.sim_time, timestep))
except:
logger.error('Exception raised, triggering end of main loop.')
raise
finally:
solver.log_stats()
```