coalescence-problem-current-sheet-scaling-study

advertisement
-- Program to solve Two-Fluid equations
--[[
Extension of the electron dissipation region in collisionless Hall MHD
Reconnection, B. P.Sullivan, Yi-Min Huang, and A. Bhattacharjee, Phys.
Plasmas, 16, 102111 (2009).
--]]
-- decomposition object to use
decomp = DecompRegionCalc2D.CartGeneral {}
-- global parameters
gasGamma = 5./3.
elcCharge = -1.0
ionCharge = 1.0
ionMass = 1.0
elcMass = ionMass/1863.
lightSpeed = 1.0
epsilon0 = 1.0
mgnErrorSpeedFactor = 1.0
Bx0 = 1/10.0 -- normalization
n0 = 1.0
cfl = 0.9
nSpecies = 2
Bx02 = Bx0*Bx0
wci = ionCharge*Bx0/ionMass
ionPlasmaFreq = math.sqrt(n0*ionCharge*ionCharge/(epsilon0*ionMass))
ionSkinDepth = lightSpeed/ionPlasmaFreq
mu0 = 1/(lightSpeed*lightSpeed*epsilon0)
VAx0 = Bx0/math.sqrt(mu0*n0*ionMass)
Bnoise = Bx0*0.00001
Vnoise = VAx0*0.00001
L = 12.8*ionSkinDepth
Lx = L
Ly = L
B0 = Bx0*2*Lucee.Pi/12.8
Ttot = Bx0*Bx0/mu0/n0 -- and assume Te = Ti
V0 = 0.1*VAx0
NX = 4097
NY = 4097
-- computational domain
grid = Grid.RectCart2D {
lower = {-Lx/2, -Ly/2},
upper = {Lx/2, Ly/2},
cells = {NX, NY},
decomposition = decomp,
periodicDirs = {0,1},
}
-- solution
q = DataStruct.Field2D {
onGrid = grid,
numComponents = 18,
ghost = {2, 2},
}
-- solution after X update
qX = DataStruct.Field2D {
onGrid = grid,
numComponents = 28,
ghost = {2, 2},
}
qDup = DataStruct.Field2D {
onGrid = grid,
numComponents = 18,
ghost = {2, 2},
}
-- updated solution
qNew = DataStruct.Field2D {
onGrid = grid,
numComponents = 18,
ghost = {2, 2},
}
-- create duplicate copy in case we need to take step again
qNewDup = DataStruct.Field2D {
onGrid = grid,
numComponents = 18,
ghost = {2, 2},
}
-- create aliases to various sub-system
elcFluid = q:alias(0, 5)
ionFluid = q:alias(5, 10)
emField = q:alias(10, 18)
elcFluidX = qX:alias(0, 5)
ionFluidX = qX:alias(5, 10)
emFieldX = qX:alias(10, 18)
elcFluidNew = qNew:alias(0, 5)
ionFluidNew = qNew:alias(5, 10)
emFieldNew = qNew:alias(10, 18)
-- alias for various fields for diagnostics
byAlias = qNew:alias(14, 15)
ezAlias = qNew:alias(12, 13)
neAlias = qNew:alias(0, 1)
uzeAlias = qNew:alias(3, 4)
uziAlias = qNew:alias(8, 9)
-- function to apply initial conditions
function init(x,y,z)
local me = elcMass
local mi = ionMass
local qe = elcCharge
local qi = ionCharge
local gasGamma1 = gasGamma-1
local pi = Lucee.Pi
math.randomseed( os.time() )
local Bx = B0*math.cos(2*pi*y/L)*math.sin(2*pi*x/L) +
Bnoise*math.random()*math.random(-1,1)
local By =-B0*math.cos(2*pi*x/L)*math.sin(2*pi*y/L) +
Bnoise*math.random()*math.random(-1,1)
local B2 = Bx*Bx+By*By
local rhoe = me*n0*(1+(Bx02-B2)/(2*n0*Ttot))
local ere = (rhoe/me)*(0.5*Ttot)/(gasGamma1)
local rhoi = mi*n0*(1+(Bx02-B2)/(2*n0*Ttot))
local izmom =
(4*pi*B0*mi/(mu0*L*qi))*math.sin(2*pi*x/L)*math.sin(2*pi*y/L) +
n0*mi*Vnoise*math.random()*math.random(-1,1)
local ixmom = rhoi*V0*math.sin(2*pi*y/L)
local iymom = rhoi*V0*math.sin(2*pi*x/L)
local eri = (rhoi/mi)*(0.5*Ttot)/(gasGamma1)+
0.5*(izmom*izmom+ixmom*ixmom+iymom*iymom)/rhoi
return rhoe, 0.0, 0.0, 0.0, ere, rhoi, ixmom, iymom, izmom, eri, 0.0, 0.0,
0.0, Bx, By, 0.0, 0.0, 0.0
end
-- set initial conditions for fields and fluids
q:set(init)
-- get ghost cells correct
q:sync()
-- copy initial conditions over
qNew:copy(q)
-- define various equations to solve
elcEulerEqn = HyperEquation.Euler {
-- gas adiabatic constant
gasGamma = gasGamma,
}
ionEulerEqn = HyperEquation.Euler {
-- gas adiabatic constant
gasGamma = gasGamma,
}
-- (Lax equations are used to fix negative pressure/density)
elcEulerLaxEqn = HyperEquation.Euler {
-- gas adiabatic constant
gasGamma = gasGamma,
-- use Lax fluxes
numericalFlux = "lax",
}
ionEulerLaxEqn = HyperEquation.Euler {
-- gas adiabatic constant
gasGamma = gasGamma,
-- use Lax fluxes
numericalFlux = "lax",
}
maxwellEqn = HyperEquation.PhMaxwell {
-- speed of light
lightSpeed = lightSpeed,
-- correction speeds
elcErrorSpeedFactor = 0.0,
mgnErrorSpeedFactor = mgnErrorSpeedFactor
}
-- updater for electron equations
elcFluidSlvrDir0 = Updater.WavePropagation2D {
onGrid = grid,
equation = elcEulerEqn,
-- one of no-limiter, min-mod, superbee, van-leer, monotonized-centered,
beam-warming
limiter = "monotonized-centered",
cfl = cfl,
cflm = 1.1*cfl,
updateDirections = {0} -- directions to update
}
-- set input/output arrays (these do not change so set it once)
elcFluidSlvrDir0:setIn( {elcFluid} )
elcFluidSlvrDir0:setOut( {elcFluidX} )
-- updater for ion equations
ionFluidSlvrDir0 = Updater.WavePropagation2D {
onGrid = grid,
equation = ionEulerEqn,
-- one of no-limiter, min-mod, superbee, van-leer, monotonized-centered,
beam-warming
limiter = "monotonized-centered",
cfl = cfl,
cflm = 1.1*cfl,
updateDirections = {0} -- directions to update
}
-- set input/output arrays (these do not change so set it once)
ionFluidSlvrDir0:setIn( {ionFluid} )
ionFluidSlvrDir0:setOut( {ionFluidX} )
-- updater for Maxwell equations
maxSlvrDir0 = Updater.WavePropagation2D {
onGrid = grid,
equation = maxwellEqn,
-- one of no-limiter, min-mod, superbee, van-leer, monotonized-centered,
beam-warming
limiter = "monotonized-centered",
cfl = cfl,
cflm = 1.1*cfl,
updateDirections = {0} -- directions to update
}
-- set input/output arrays (these do not change so set it once)
maxSlvrDir0:setIn( {emField} )
maxSlvrDir0:setOut( {emFieldX} )
-- updater for electron equations
elcFluidSlvrDir1 = Updater.WavePropagation2D {
onGrid = grid,
equation = elcEulerEqn,
-- one of no-limiter, min-mod, superbee, van-leer, monotonized-centered,
beam-warming
limiter = "monotonized-centered",
cfl = cfl,
cflm = 1.1*cfl,
updateDirections = {1} -- directions to update
}
-- set input/output arrays (these do not change so set it once)
elcFluidSlvrDir1:setIn( {elcFluidX} )
elcFluidSlvrDir1:setOut( {elcFluidNew} )
-- updater for ion equations
ionFluidSlvrDir1 = Updater.WavePropagation2D {
onGrid = grid,
equation = ionEulerEqn,
-- one of no-limiter, min-mod, superbee, van-leer, monotonized-centered,
beam-warming
limiter = "monotonized-centered",
cfl = cfl,
cflm = 1.1*cfl,
updateDirections = {1} -- directions to update
}
-- set input/output arrays (these do not change so set it once)
ionFluidSlvrDir1:setIn( {ionFluidX} )
ionFluidSlvrDir1:setOut( {ionFluidNew} )
-- updater for Maxwell equations
maxSlvrDir1 = Updater.WavePropagation2D {
onGrid = grid,
equation = maxwellEqn,
-- one of no-limiter, min-mod, superbee, van-leer, monotonized-centered,
beam-warming
limiter = "monotonized-centered",
cfl = cfl,
cflm = 1.1*cfl,
updateDirections = {1} -- directions to update
}
-- set input/output arrays (these do not change so set it once)
maxSlvrDir1:setIn( {emFieldX} )
maxSlvrDir1:setOut( {emFieldNew} )
-- (Lax equation solver are used to fix negative pressure/density)
-- updater for electron equations
elcLaxSlvr = Updater.WavePropagation2D {
onGrid = grid,
equation = elcEulerLaxEqn,
-- one of no-limiter, min-mod, superbee, van-leer, monotonized-centered,
beam-warming
limiter = "zero",
cfl = cfl,
cflm = 1.1*cfl,
}
-- set input/output arrays (these do not change so set it once)
elcLaxSlvr:setIn( {elcFluid} )
elcLaxSlvr:setOut( {elcFluidNew} )
-- updater for ion equations
ionLaxSlvr = Updater.WavePropagation2D {
onGrid = grid,
equation = ionEulerLaxEqn,
-- one of no-limiter, min-mod, superbee, van-leer, monotonized-centered,
beam-warming
limiter = "zero",
cfl = cfl,
cflm = 1.1*cfl,
}
-- set input/output arrays (these do not change so set it once)
ionLaxSlvr:setIn( {ionFluid} )
ionLaxSlvr:setOut( {ionFluidNew} )
maxSlvr = Updater.WavePropagation2D {
onGrid = grid,
equation = maxwellEqn,
-- one of no-limiter, min-mod, superbee, van-leer, monotonized-centered,
beam-warming
limiter = "monotonized-centered",
cfl = cfl,
cflm = 1.1*cfl,
}
-- set input/output arrays (these do not change so set it once)
maxSlvr:setIn( {emField} )
maxSlvr:setOut( {emFieldNew} )
-- updater for two-fluid sources
sourceSlvr = Updater.ImplicitFiveMomentSrc2D {
-- grid on which to run updater
onGrid = grid,
-- number of fluids
numFluids = 2,
-- species charge
charge = {elcCharge, ionCharge},
-- species mass
mass = {elcMass, ionMass},
-- premittivity of free space
epsilon0 = epsilon0,
-- linear solver to use: one of partialPivLu or colPivHouseholderQr
linearSolver = "partialPivLu",
-- has static magnetic field
hasStaticField = false,
}
-- function to apply boundary conditions
function applyBc(fld, t)
-- periodic
fld:sync()
end
-- apply BCs to initial conditions
applyBc(q)
applyBc(qNew)
function updateSource(inpElc, inpIon, inpEm, tCurr, tEnd)
sourceSlvr:setOut( {inpElc, inpIon, inpEm} )
sourceSlvr:setCurrTime(tCurr)
sourceSlvr:advance(tEnd)
end
-- function to update the fluid and field using dimensional splitting
function updateFluidsAndField(tCurr, t)
local myStatus = true
local myDtSuggested = 1e3*math.abs(t-tCurr)
-- X-direction updates
for i,slvr in ipairs({elcFluidSlvrDir0, ionFluidSlvrDir0, maxSlvrDir0}) do
slvr:setCurrTime(tCurr)
local status, dtSuggested = slvr:advance(t)
myStatus = status and myStatus
myDtSuggested = math.min(myDtSuggested, dtSuggested)
end
-- apply BCs to intermediate update after X sweep
applyBc(qX)
-- Y-direction updates
for i,slvr in ipairs({elcFluidSlvrDir1, ionFluidSlvrDir1, maxSlvrDir1}) do
slvr:setCurrTime(tCurr)
local status, dtSuggested = slvr:advance(t)
myStatus = status and myStatus
myDtSuggested = math.min(myDtSuggested, dtSuggested)
end
return myStatus, myDtSuggested
end
-- function to take one time-step
function solveTwoFluidSystem(tCurr, t)
local dthalf = 0.5*(t-tCurr)
-- update source term
updateSource(elcFluid, ionFluid, emField, tCurr, tCurr+dthalf)
applyBc(q)
-- update fluids and fields
local status, dtSuggested = updateFluidsAndField(tCurr, t)
-- update source terms
updateSource(elcFluidNew, ionFluidNew, emFieldNew, tCurr, tCurr+dthalf)
applyBc(qNew)
return status, dtSuggested
end
-- function to take one time-step
function solveTwoFluidLaxSystem(tCurr, t)
local dthalf = 0.5*(t-tCurr)
-- update source term
updateSource(elcFluid, ionFluid, emField, tCurr, tCurr+dthalf)
applyBc(q)
-- advance electrons
elcLaxSlvr:setCurrTime(tCurr)
local elcStatus, elcDtSuggested = elcLaxSlvr:advance(t)
-- advance ions
ionLaxSlvr:setCurrTime(tCurr)
local ionStatus, ionDtSuggested = ionLaxSlvr:advance(t)
-- advance fields
maxSlvr:setCurrTime(tCurr)
local maxStatus, maxDtSuggested = maxSlvr:advance(t)
-- check if any updater failed
local status = false
local dtSuggested = math.min(elcDtSuggested, ionDtSuggested,
maxDtSuggested)
if (elcStatus and ionStatus and maxStatus) then
status = true
end
-- update source terms
updateSource(elcFluidNew, ionFluidNew, emFieldNew, tCurr, tCurr+dthalf)
applyBc(qNew)
return status, dtSuggested
end
-- dynvector to store integrated flux
byFlux = DataStruct.DynVector { numComponents = 1 }
byFluxCalc = Updater.IntegrateFieldAlongLine2D {
onGrid = grid,
-- start cell
startCell = {0, NY/2},
-- direction to integrate in
dir = 0,
-- number of cells to integrate
numCells = NX,
-- integrand
integrand = function (by)
return math.abs(by)
end,
}
byFluxCalc:setIn( {byAlias} )
byFluxCalc:setOut( {byFlux} )
-- dynvector to store Ez at X-point
xpointEz = DataStruct.DynVector { numComponents = 1 }
xpointEzRec = Updater.RecordFieldInCell2D {
onGrid = grid,
-- index of cell to record
cellIndex = {(NX-1)/2, (NY-1)/2},
}
xpointEzRec:setIn( {ezAlias} )
xpointEzRec:setOut( {xpointEz} )
-- dynvector to store number density at X-point
xpointNe = DataStruct.DynVector { numComponents = 1 }
xpointNeRec = Updater.RecordFieldInCell2D {
onGrid = grid,
-- index of cell to record
cellIndex = {(NX-1)/2, (NY-1)/2},
}
xpointNeRec:setIn( {neAlias} )
xpointNeRec:setOut( {xpointNe} )
-- dynvector to store electron uz at X-point
xpointUze = DataStruct.DynVector { numComponents = 1 }
xpointUzeRec = Updater.RecordFieldInCell2D {
onGrid = grid,
-- index of cell to record
cellIndex = {(NX-1)/2, (NY-1)/2},
}
xpointUzeRec:setIn( {uzeAlias} )
xpointUzeRec:setOut( {xpointUze} )
-- dynvector to store ion uz at X-point
xpointUzi = DataStruct.DynVector { numComponents = 1 }
xpointUziRec = Updater.RecordFieldInCell2D {
onGrid = grid,
-- index of cell to record
cellIndex = {(NX-1)/2, (NY-1)/2},
}
xpointUziRec:setIn( {uziAlias} )
xpointUziRec:setOut( {xpointUzi} )
-- compute diagnostic
function calcDiagnostics(tCurr, t)
for i,diag in ipairs({byFluxCalc, xpointEzRec, xpointNeRec, xpointUzeRec,
xpointUziRec}) do
diag:setCurrTime(tCurr)
diag:advance(t)
end
end
-- advance solution from tStart to tEnd, using optimal time-steps.
function advanceFrame(tStart, tEnd, initDt)
local step = 1
local tCurr = tStart
local myDt = initDt
local tfStatus, tfDtSuggested
local useLaxSolver = false
while true do
qDup:copy(q)
qNewDup:copy(qNew)
if (tCurr+myDt > tEnd) then -- hit tEnd exactly
myDt = tEnd-tCurr
end
Lucee.logInfo (string.format(" Taking step %d at time %g with dt %g",
step, tCurr, myDt))
if (useLaxSolver) then
-- (call Lax solver if positivity violated)
tfStatus, tfDtSuggested = solveTwoFluidLaxSystem(tCurr, tCurr+myDt)
useLaxSolver = false
else
tfStatus, tfDtSuggested = solveTwoFluidSystem(tCurr, tCurr+myDt)
end
if (tfStatus == false) then
Lucee.logInfo (string.format(" ** Time step %g too large! Will retake
with dt %g", myDt, tfDtSuggested))
myDt = tfDtSuggested
qNew:copy(qNewDup)
q:copy(qDup)
elseif ((elcEulerEqn:checkInvariantDomain(elcFluidNew) == false)
or (ionEulerEqn:checkInvariantDomain(ionFluidNew) == false)) then
Lucee.logInfo (string.format("** Negative pressure or density at %g!
Will retake step with Lax fluxes", tCurr+myDt))
q:copy(qDup)
qNew:copy(qNewDup)
useLaxSolver = true
else
if (qNew:hasNan()) then
Lucee.logInfo (string.format(" ** Nan occured at %g! Stopping
simulation", tCurr))
break
end
--calcDiagnostics(tCurr, tCurr+myDt)
q:copy(qNew)
myDt = tfDtSuggested
tCurr = tCurr + myDt
step = step + 1
if (tCurr >= tEnd) then
break
end
end
end
return tfDtSuggested
end
function writeFrame(frame, tCurr)
qNew:write(string.format("q_%d.h5", frame), tCurr )
byFlux:write( string.format("byFlux_%d.h5", frame) )
xpointEz:write(string.format("xpointEz_%d.h5", frame) )
xpointNe:write(string.format("xpointNe_%d.h5", frame) )
xpointUze:write(string.format("xpointUze_%d.h5", frame) )
xpointUzi:write(string.format("xpointUzi_%d.h5", frame) )
end
-- compute diagnostics and write out initial conditions
--calcDiagnostics(0.0, 0.0)
writeFrame(0, 0.0)
dtSuggested = 1.0 -- initial time-step to use (this will be discarded and
adjusted to CFL value)
-- parameters to control time-stepping
tStart = 0.0
tEnd = 12/wci
nFrames = 12
tFrame = (tEnd-tStart)/nFrames -- time between frames
tCurr = tStart
-- main loop
for frame = 1, nFrames do
Lucee.logInfo (string.format("-- Advancing solution from %g to %g", tCurr,
tCurr+tFrame))
-- advance solution between frames
dtSuggested = advanceFrame(tCurr, tCurr+tFrame, dtSuggested)
-- write out data
writeFrame(frame, tCurr+tFrame)
tCurr = tCurr+tFrame
Lucee.logInfo ("")
end
Download