Skip to content

Commit

Permalink
CHG: initial ice sheet model
Browse files Browse the repository at this point in the history
  • Loading branch information
MathieuMorlighem committed Jan 30, 2022
1 parent 3f53a47 commit d57df84
Show file tree
Hide file tree
Showing 36 changed files with 7,247 additions and 1 deletion.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# dJUICE
differentiable JUlia ICE model
(Mathieu Morlighem, 2022/01)

Authors:
- Mathieu Morlighem, Dartmouth College

License: MIT
2 changes: 2 additions & 0 deletions core/analyses/analysis.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#Analysis class definitions
abstract type Analysis end
275 changes: 275 additions & 0 deletions core/analyses/masstransportanalysis.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
#MasstransportAnalysis class definition
struct MasstransportAnalysis <: Analysis#{{{
end #}}}

#Model Processing
function CreateConstraints(analysis::MasstransportAnalysis,constraints::Vector{Constraint},md::model) #{{{

#load constraints from model
spcthickness = md.masstransport.spcthickness

count = 1
for i in 1:md.mesh.numberofvertices
if ~isnan(spcthickness[i])
push!(constraints,Constraint(count,i,1,spcthickness[i]))
count+=1
end
end

end#}}}
function CreateNodes(analysis::MasstransportAnalysis,nodes::Vector{Node},md::model) #{{{

numdof = 1
for i in 1:md.mesh.numberofvertices
push!(nodes,Node(i,i,true,true,numdof,-ones(Int64,numdof), ones(Int64,numdof), -ones(Int64,numdof), zeros(numdof)))
end
end#}}}
function UpdateElements(analysis::MasstransportAnalysis,elements::Vector{Tria}, inputs::Inputs, md::model) #{{{

#Provide node indices to element
for i in 1:md.mesh.numberofelements
Update(elements[i],inputs,i,md,P1Enum)
end

#Add necessary inputs to perform this analysis
FetchDataToInput(md,inputs,elements,md.geometry.thickness,ThicknessEnum)
FetchDataToInput(md,inputs,elements,md.geometry.surface,SurfaceEnum)
FetchDataToInput(md,inputs,elements,md.geometry.base,BaseEnum)
FetchDataToInput(md,inputs,elements,md.geometry.bed,BedEnum)
FetchDataToInput(md,inputs,elements,md.basalforcings.groundedice_melting_rate./md.constants.yts,BasalforcingsGroundediceMeltingRateEnum)
FetchDataToInput(md,inputs,elements,md.basalforcings.floatingice_melting_rate./md.constants.yts,BasalforcingsFloatingiceMeltingRateEnum)
FetchDataToInput(md,inputs,elements,md.smb.mass_balance./md.constants.yts,SmbMassBalanceEnum)
FetchDataToInput(md,inputs,elements,md.mask.ice_levelset, MaskIceLevelsetEnum)
FetchDataToInput(md,inputs,elements,md.mask.ocean_levelset, MaskOceanLevelsetEnum)
FetchDataToInput(md,inputs,elements,md.initialization.vx./md.constants.yts,VxEnum)
FetchDataToInput(md,inputs,elements,md.initialization.vy./md.constants.yts,VyEnum)

end#}}}
function UpdateParameters(analysis::MasstransportAnalysis,parameters::Parameters,md::model) #{{{

AddParam(parameters, md.masstransport.min_thickness, MasstransportMinThicknessEnum)
AddParam(parameters, md.masstransport.stabilization, MasstransportStabilizationEnum)

end#}}}

#Finite Element Analysis
function Core(analysis::MasstransportAnalysis,femmodel::FemModel)# {{{

println(" computing mass transport")
SetCurrentConfiguration!(femmodel, analysis)

InputDuplicatex(femmodel, ThicknessEnum, ThicknessOldEnum)
InputDuplicatex(femmodel, BaseEnum, BaseOldEnum)
InputDuplicatex(femmodel, SurfaceEnum, SurfaceOldEnum)

solutionsequence_linear(femmodel,analysis)

#Save output
RequestedOutputsx(femmodel, [ThicknessEnum, SurfaceEnum, BaseEnum])

end #}}}
function CreateKMatrix(analysis::MasstransportAnalysis,element::Tria)# {{{

#Return if there is no ice in this element
if(!IsIceInElement(element)) return end

#Internmediaries
numnodes = 3

#Initialize Element matrix and basis function derivatives
Ke = ElementMatrix(element.nodes)
dbasis = Matrix{Float64}(undef,numnodes,2)
basis = Vector{Float64}(undef,numnodes)

#Retrieve all inputs and parameters
xyz_list = GetVerticesCoordinates(element.vertices)
vx_input = GetInput(element, VxEnum)
vy_input = GetInput(element, VyEnum)
dt = FindParam(Float64, element, TimesteppingTimeStepEnum)
stabilization = FindParam(Int64, element, MasstransportStabilizationEnum)

h = CharacteristicLength(element)

#Start integrating
gauss = GaussTria(2)
for ig in 1:gauss.numgauss

Jdet = JacobianDeterminant(xyz_list, gauss)
NodalFunctionsDerivatives(element, dbasis, xyz_list, gauss)
NodalFunctions(element, basis, gauss, ig, P1Enum)

#Transient term
for i in 1:numnodes
for j in 1:numnodes
Ke.values[i ,j] += gauss.weights[ig]*Jdet*basis[i]*basis[j]
end
end

#Advection term
vx = GetInputValue(vx_input, gauss, ig)
vy = GetInputValue(vy_input, gauss, ig)
dvx = GetInputDerivativeValue(vx_input, xyz_list, gauss, ig)
dvy = GetInputDerivativeValue(vy_input, xyz_list, gauss, ig)
for i in 1:numnodes
for j in 1:numnodes
#\phi_i \phi_j \nabla\cdot v
Ke.values[i ,j] += dt*gauss.weights[ig]*Jdet*basis[i]*basis[j]*(dvx[1] + dvy[2])
#\phi_i v\cdot\nabla\phi_j
Ke.values[i ,j] += dt*gauss.weights[ig]*Jdet*basis[i]*(vx*dbasis[j,1] + vy*dbasis[j,2])
end
end

#Stabilization
if(stabilization==0)
#do nothing
elseif (stabilization==1)
vx = GetInputAverageValue(vx_input)
vy = GetInputAverageValue(vy_input)
D = dt*gauss.weights[ig]*Jdet*[h/2*abs(vx) 0; 0 h/2*abs(vy)]
for i in 1:numnodes; for j in 1:numnodes
Ke.values[i ,j] += (dbasis[i,1]*(D[1,1]*dbasis[j,1] + D[1,2]*dbasis[j,2]) +
dbasis[i,2]*(D[2,1]*dbasis[j,1] + D[2,2]*dbasis[j,2]))
end end
else
error("Stabilization ",stabilization, " not supported yet")
end
end

return Ke
end #}}}
function CreatePVector(analysis::MasstransportAnalysis,element::Tria)# {{{

#Return if there is no ice in this element
if(!IsIceInElement(element)) return end

#Internmediaries
numnodes = 3

#Initialize Element vectro and basis functions
pe = ElementVector(element.nodes)
basis = Vector{Float64}(undef,numnodes)

#Retrieve all inputs and parameters
xyz_list = GetVerticesCoordinates(element.vertices)
H_input = GetInput(element, ThicknessEnum)
gmb_input = GetInput(element, BasalforcingsGroundediceMeltingRateEnum)
fmb_input = GetInput(element, BasalforcingsFloatingiceMeltingRateEnum)
smb_input = GetInput(element, SmbMassBalanceEnum)
olevelset_input = GetInput(element, MaskOceanLevelsetEnum)
dt = FindParam(Float64, element, TimesteppingTimeStepEnum)
stabilization = FindParam(Int64, element, MasstransportStabilizationEnum)

#How much is actually grounded?
phi=GetGroundedPortion(element, xyz_list)

#Start integrating
gauss = GaussTria(3)
for ig in 1:gauss.numgauss

Jdet = JacobianDeterminant(xyz_list, gauss)
NodalFunctions(element, basis, gauss, ig, P1Enum)

smb = GetInputValue(smb_input, gauss, ig)
H = GetInputValue(H_input, gauss, ig)

#Only apply melt on fully floating cells
if(phi<0.00000001)
mb = GetInputValue(fmb_input, gauss, ig)
else
mb = GetInputValue(gmb_input, gauss, ig)
end

for i in 1:numnodes
pe.values[i] += gauss.weights[ig]*Jdet*(H + dt*(smb - mb))*basis[i]
end
end

return pe
end #}}}
function GetSolutionFromInputs(analysis::MasstransportAnalysis,ug::IssmVector,element::Tria) #{{{

#Get dofs for this finite element
doflist = GetDofList(element,GsetEnum)
@assert length(doflist)==3

#Fetch inputs
thickness_input = GetInput(element, ThicknessEnum)

#Loop over each node and enter solution in ug
count = 0
gauss=GaussTria(P1Enum)
for i in 1:gauss.numgauss
thickness = GetInputValue(thickness_input, gauss, i)

count += 1
ug.vector[doflist[count]] = thickness
end

#Make sure we reached all the values
@assert count==length(doflist)

end#}}}
function InputUpdateFromSolution(analysis::MasstransportAnalysis,ug::Vector{Float64},element::Tria) #{{{

#Get dofs for this finite element
doflist = GetDofList(element,GsetEnum)

#Get solution vector for this element
numdof = 3
values = Vector{Float64}(undef,numdof)
for i in 1:numdof values[i]=ug[doflist[i]] end

#Get some parameters
rho_water = FindParam(Float64, element, MaterialsRhoSeawaterEnum)
rho_ice = FindParam(Float64, element, MaterialsRhoIceEnum)
H_min = FindParam(Float64, element, MasstransportMinThicknessEnum)

#Now split solution vector into x and y components
numnodes = 3
thickness = Vector{Float64}(undef,numnodes)
for i in 1:numnodes
thickness[i]=values[i]
@assert isfinite(thickness[i])

#Enforce minimum thickness
if(thickness[i]<H_min)
thickness[i] = H_min
end
end
AddInput(element, ThicknessEnum, thickness, P1Enum)

#Update bed and surface accordingly
newthickness = Vector{Float64}(undef,3)
oldthickness = Vector{Float64}(undef,3)
oldbase = Vector{Float64}(undef,3)
oldsurface = Vector{Float64}(undef,3)
phi = Vector{Float64}(undef,3)
bed = Vector{Float64}(undef,3)
GetInputListOnVertices!(element, newthickness, ThicknessEnum)
GetInputListOnVertices!(element, oldthickness, ThicknessOldEnum)
GetInputListOnVertices!(element, oldbase, BaseOldEnum)
GetInputListOnVertices!(element, oldsurface, SurfaceOldEnum)
GetInputListOnVertices!(element, phi, MaskOceanLevelsetEnum)
GetInputListOnVertices!(element, bed, BedEnum)
sealevel = zeros(3)
newsurface = Vector{Float64}(undef,3)
newbase = Vector{Float64}(undef,3)

for i in 1:3
if(phi[i]>0.)
#this is grounded ice: just add thickness to base.
newsurface[i] = bed[i]+newthickness[i] #surface = bed + newthickness
newbase[i] = bed[i] #new base at new bed
else
#this is an ice shelf: hydrostatic equilibrium
newsurface[i] = newthickness[i]*(1-rho_ice/rho_water) + sealevel[i]
newbase[i] = newthickness[i]*(-rho_ice/rho_water) + sealevel[i]
end
end

AddInput(element, SurfaceEnum, newsurface, P1Enum)
AddInput(element, BaseEnum, newbase, P1Enum)
end#}}}
function UpdateConstraints(analysis::MasstransportAnalysis, femmodel::FemModel) #{{{
SetActiveNodesLSMx(femmodel)
end#}}}
Loading

0 comments on commit d57df84

Please sign in to comment.